前述のリストのようなクラスの場合,繰り返しを実現するために, nextなどのメンバ変数を参照しなければならない.
List<int> *p;
....
for (List<int> *q = p; q != NULL; q = q->next) {
処理
}
これをやるにはnextをpublicにしなければならないが,それは
あまり好まれないので,代わりにnextの内容を返す関数を
作ったりする.
template <class T>
class List {
protected:
List<T> *next;
public:
....
List<T> *next_item() { return next; }
};
List<int> *p;
....
for (List<int> *q = p; q != NULL; q = q->next_item()) {
処理
}
しかし,これでもList<T>の内部構造が見えすぎる感じがする.
そこで,こんなことをする場合がある.
template <class T>
class List {
friend class ListIter<T>;
protected:
List<T> *next;
public:
....
};
template <class T>
class ListIter {
protected:
List<T>* list;
public:
ListIter<T>(List<T>* p) { list = p; }
int null() { return list == 0; }
void operator ++ () { if (list) list = list->next; }
T& operator *() { return list->nakami; }
};
ListIter<T>というクラスでは,++と*を
再定義している.このListIter<T>を使うと,List
に関する繰り返しは,こんな形で書ける.
List<int> *p;
...
for (ListIter<int> i(p); !i.null(); ++i) {
printf("%d¥n",*i);
}
ListIterは,Listに関する繰り返しを封じ込めたクラスだ.
これを使えば,配列に関する繰り返しのような感覚で,Listに
ついての繰り返しを記述することができる.こういうクラスをイテレータクラス
と呼ぶ.イテレータクラスを定義しておけば,それが指しているクラスの実装が
連結リストか配列か...ということを全く気にしなくてよくなる.