В классе slist_base нет функций для просмотра списка, можно только вставлять и удалять элементы. Однако, в нем описывается как друг класс slist_base_iter, поэтому можно определить подходящий для списка итератор. Вот один из возможных, заданный в том стиле, какой был показан в §7.8:
class slist_base_iter { slink* ce; // текущий элемент slist_base* cs; // текущий список public: inline slist_base_iter(slist_base& s); inline slink* operator()() };
slist_base_iter::slist_base_iter(slist_base& s) { cs = &s; ce = cs->last; }
slink* slist_base_iter::operator()() // возвращает 0, когда итерация кончается { slink* ret = ce ? (ce=ce->next) : 0; if (ce == cs->last) ce = 0; return ret; }
Исходя из этих определений, легко получить итераторы для Slist и Islist. Сначала надо определить дружественные классы для итераторов по соответствующим контейнерным классам:
template<class T> class Islist_iter;
template<class T> class Islist { friend class Islist_iter<T>; // ... };
template<class T> class Slist_iter;
template<class T> class Slist { friend class Slist_iter<T>; // ... };
Обратите внимание, что имена итераторов появляются без определения их шаблонного класса. Это способ определения в условиях взаимной зависимости шаблонов типа.
Теперь можно определить сами итераторы:
template<class T> class Islist_iter : private slist_base_iter { public: Islist_iter(Islist<T>& s) : slist_base_iter(s) { }
T* operator()() { return (T*) slist_base_iter::operator()(); } };
template<class T> class Slist_iter : private slist_base_iter { public: Slist_iter(Slist<T>& s) : slist_base_iter(s) { } inline T* operator()(); };
T* Slist_iter::operator()() { return ((Tlink<T>*) slist_base_iter::operator()())->info; }
Заметьте, что мы опять использовали прием, когда из одного базового класса строится семейство производных классов (а именно, шаблонный класс). Мы используем наследование, чтобы выразить общность классов и избежать ненужного дублирования функций. Трудно переоценить стремление избежать дублирования функций при реализации таких простых и часто используемых классов как списки и итераторы. Пользоваться этими итераторами можно так: