8

ビジターパターンは、C ++でメソッドパラメータータイプの識別(事実上、メンバーのクラスではなく、パラメーターに対する単一のディスパッチ)を実現するための最速の方法ですか?まだ知られていないサブタイプの要素で呼び出したい正確なメソッドを知っている可能性があるため、のように追加の仮想メソッド呼び出しを常に行うことV::visit(A *)A::accept(V &v) { v.visit(this); }望ましくありません。

// Is the Visitor pattern recommended here?  (E inherits D inherits B.)
class Foo {
public:
  virtual void visit(B *) { result = 3; }
  virtual void visit(D *) { result = 4; }
  virtual void visit(E *) { result = 5; }
private:
  int result;
}; // class Foo

// Need to add generic interface to B and its children ...
class B {
public:
  virtual void accept(class Foo &f) { f.visit(this); }
}; // class B

次の機能と同等のものが欲しいのですが、O(1)コストが必要です。これはstd::type_info、constexpr / switchableにできないため、dynamic_cast <>またはtypeid()ラダーでは不可能なAFAIKです。

// O(n) search cost might get nasty with bigger hierarchies.
int foo(B *b) {
  if (typeid(b) == typeid(B *)) { return 1; }
  if (typeid(b) == typeid(D *)) { return 2; }
  if (typeid(b) == typeid(E *)) { return 3; }
  return -1;
}

ここでの私のオプションは何ですか?アドバイスありがとうございます!

編集:異なるメソッドタイプに複数の署名が必要ないように、フィールドを介して結果をフィードするようにサンプルコードを変更しました。ありがとう、モーリス!

最終決定: Visitor Patternの必須のダブルディスパッチコストが気に入らないことに加えて、オーバーロードのインターフェイスの肥大化を避けたかったのfoo()ですが、これを行うための既知のクリーンなパターンはないと思います。私は結局、まっすぐな静的オーバーロードを実行して、それを1日と呼びました。とにかく、関数内にオーバーロードをカプセル化したいのは、せいぜい疑わしい目標でしょう。応答してくれてありがとう、モーリス。

4

1 に答える 1

3

実際、インターフェースを複製する必要はありません。訪問者のサブクラスは、操作の詳細を処理できます。あなたの場合:

class Visitor {
    virtual void visit(B*) = 0;
    virtual void visit(D*) = 0;
    virtual void visit(E*) = 0;
}

class Foo: public Visitor {
private:
    int result;
public:
    void visit(B*) { result = 3; }
    void visit(D*) { result = 4; }
    void visit(E*) { result = 5; }
    int apply(A* a) {
        a->accept(this);
        return result;
    }
}

したがって、各クラスに必要なaccept()メソッドは1つだけです。

私が考えることができるビジターパターンのすべての代替案には、ある種のランタイム検索が含まれるため、そうです、IMHO、ビジターパターンが最速の方法です。

于 2010-08-31T17:47:41.873 に答える