一般的なケースでは、少なくともきれいにではないと思います。
少なくとも通常定義されているように、反復子は同種のコレクションを処理することを期待しています。つまり、イテレータは通常次のように定義されます。
template <class Element>
class iterator // ...
...そのため、特定のイテレータは特定の 1 つのタイプの要素のみを処理できます。異なる型を操作するためにできることのほとんどは、基本クラスへの (ポインター/参照) へのイテレーターを作成し、派生クラスのオブジェクトを処理できるようにすることです。
対照的に、次のようなビジターを作成するのは非常に簡単です。
class MyVisitor {
public:
void VisitOneType(OneType const *element);
void VisitAnotherType(AnotherType const *element);
};
OneType
これは、またはのいずれかのノードを訪問できますAnotherType
。2 つが完全に無関係であってもです。基本的に、 Visitor クラスには、アクセスできるさまざまなタイプのクラスVisit
ごとに 1 つのメンバー関数があります。
少し異なる方向から見ると、イテレータは基本的に、1 つのタイプのオブジェクトに対してのみ機能するビジターの特殊な形式です。無関係なタイプのオブジェクトを訪問する能力を失う代わりに、訪問パターンをもう少し制御できます。
1 つのタイプのみを処理する必要がある場合 (ただし、その 1 つのタイプが基本クラスであり、アクセスされたオブジェクトがさまざまな派生型である場合)、明白な方法は、オブジェクト (Tree
ノード、ノード、あなたの例では)、それvisit
が呼び出されると、訪問しているノードのアドレスをイテレータをサポートするコレクションにコピーするだけです:
template <class T>
class Bridge {
std::vector<T *> nodes;
public:
virtual void visit(T *n) {
nodes.push_back(n);
}
typedef std::vector<T *>::iterator iterator;
iterator begin() { return nodes.begin(); }
iterator end() { return nodes.end(); }
};
これを使用するには、2 段階のプロセスがあります。まず、訪問者が通常行うようにノードにアクセスします。次に、イテレータを提供する他のコレクションと同じように、関心のあるノードをまとめて反復処理できます。その時点で、訪問パターンは、ブリッジで使用するコレクションによって提供されるイテレータのクラスによってのみ制限されます。