Вначале определим простой список, в котором предполагается, что в каждом заносимом в список объекте есть поле связи. Потом этот список будет использоваться как строительный материал для создания более общих списков, в которых объект не обязан иметь поле связи. Сперва в описаниях классов будет приведена только общая часть, а реализация будет дана в следующем разделе. Это делается за тем, чтобы вопросы проектирования классов не затемнялись деталями их реализации.
Начнем с типа slink, определяющего поле связи в односвязном списке:
struct slink { slink* next; slink() { next = 0; } slink(slink* p) { next = p; } };
Теперь можно определить класс, который может содержать объекты любого, производного от slink, класса:
class slist_base { // ... public: int insert(slink*); // добавить в начало списка int append(slink*); // добавить к концу списка slink* get(); // удалить и возвратить начало списка // ... };
Такой класс можно назвать списком с принудительной связью, поскольку его можно использовать только в том случае, когда все элементы имеют поле slink, которое используется как указатель на slist_base. Само имя slist_base (базовый односвязный список) говорит, что этот класс будет использоваться как базовый для односвязных списочных классов. Как обычно, при разработке семейства родственных классов возникает вопрос, как выбирать имена для различных членов семейства. Поскольку имена классов не могут перегружаться, как это делается для имен функций, для обуздания размножения имен перегрузка нам не поможет.
Класс slist_base можно использовать так:
void f() { slist_base slb; slb.insert(new slink); // ... slink* p = slb.get(); // ... delete p; }
Но поскольку структура slink не может содержать никакой информации помимо связи, этот пример не слишком интересен. Чтобы воспользоваться slist_base, надо определить полезный, производный от slink, класс. Например, в трансляторе используются узлы дерева программы name (имя), которые приходится связывать в список:
class name : public slink { // ... };