next up previous
Next: コピーコンストラクタ Up: C++のめんどくさい利用法 Previous: テンプレート

イテレータ

前述のリストのようなクラスの場合,繰り返しを実現するために, 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に ついての繰り返しを記述することができる.こういうクラスをイテレータクラス と呼ぶ.イテレータクラスを定義しておけば,それが指しているクラスの実装が 連結リストか配列か...ということを全く気にしなくてよくなる.



Akinori ITO
Thu Aug 7 15:05:13 JST 1997