Язык программирования C++ для профессионалов



           

Абстрактные типы - часть 4


Конечно, все эти ответы связаны. В качестве примера [2] рассмотрим понятие генератора итераций. Требуется определить генератор итераций (в дальнейшем итератор) для любого типа так, чтобы с его помощью можно было порождать последовательность объектов этого типа. Естественно для этого нужно использовать уже упоминавшийся класс slist. Однако, нельзя просто определить общий итератор над slist, или даже над set, поскольку общий итератор должен допускать итерации и более сложных объектов, не являющихся множествами, например, входные потоки или функции, которые при очередном вызове дают следующее значение итерации. Значит нам нужны и множество и итератор, и в тоже время нежелательно дублировать конкретные типы, которые являются очевидными реализациями различных видов множеств и итераторов. Можно графически представить желательную структуру классов так:

Здесь классы set и iter предоставляют интерфейсы, а slist и stream являются частными классами и представляют реализации. Очевидно, нельзя перевернуть эту иерархию классов и, предоставляя общие интерфейсы, строить производные конкретные типы от абстрактных классов. В такой иерархии каждая полезная операция над каждым полезным абстрактным понятием должна представляться в общем абстрактном базовом классе. Дальнейшее обсуждение этой темы содержится в §13.6.

Приведем пример простого абстрактного типа, являющегося итератором объектов типа T:

class iter { virtual T* first() = 0; virtual T* next() = 0; virtual ~iter() { } };

class slist_iter : public iter, private slist { slink* current_elem; public: T* first(); T* next();

slist_iter() : current_elem(0) { } };

class input_iter : public iter { isstream& is; public: T* first(); T* next();

input_iter(istream& r) : is(r) { } };

Можно таким образом использовать определенные нами типы:

void user(const iter& it) { for (T* p = it.first(); p; p = it.next()) { // ... } }

void caller() { slist_iter sli; input_iter ii(cin);

// заполнение sli

user(sli); user(ii); }

Мы применили конкретный тип для реализации абстрактного типа, но можно использовать его и независимо от абстрактных типов или просто вводить такие типы для повышения эффективности программы, см. также §13.5. Кроме того, можно использовать один конкретный тип для реализации нескольких абстрактных типов.

В разделе §13.9 описывается более гибкий итератор. Для него зависимость от реализации, которая поставляет подлежащие итерации объекты, определяется в момент инициализации и может изменяться в ходе выполнения программы.




Содержание  Назад  Вперед