5

次の階層について考えてみます。

class Base
{
   virtual void Method() = 0;
   virtual void Accept(Visitor *iVisitor) = 0;
};
class Derived1: public Base
{
   virtual void Method(){//impl}
   virtual void Accept(Visitor *iVisitor)
   {
        iVisitor->Visit(this);
   }
};
class Derived2: public Base
{
   virtual void Method(){//impl}
   virtual void Accept(Visitor *iVisitor)
   {
       iVisitor->Visit(this);
   }
};

およびビジタークラス:

class VisitorInterface
{
    virtual void Visit(Derived1 * param);
    virtual void Visit(Derived2 * param);
}
class Visitor: public VisitorInterface
{
    void Visit(Derived1 * param){}
    void Visit(Derived2 * param){}
}

通常、オーバーロードメソッドがパラメータータイプに依存する場合、ビジターパターンを使用してダブルディスパッチを実現しますが、基本クラスへのポインターしかありません。

例えば:

void foo(Visitor *visitorPtr, Base * basePtr)
{
    basePtr->Accept(visitorPtr);    
} 

仮想関数の動的バインディングは、メソッドが呼び出されたオブジェクトでのみ発生し、そのパラメーター(派生型)では発生しないため、これがダブルディスパッチを実現する唯一の方法だと思います。

今、私は新しい状況に遭遇しました。そこでは、複数のパラメーターでオーバーロードする一種のVisitメソッドが必要です。このようなもの:

class VisitorInterfaceMultiple
{
    virtual void Visit(Derived1 * param1, Derived2 * param2);
    virtual void Visit(Derived2 * param1, Derived3 *param2);
}

acceptメソッドはパラメーターの1つでのみ呼び出されるため、従来のビジターパターンソリューションを使用できません。

私の質問は、この状況で使用できる同様のビジターパターンソリューションまたは同様のものが存在するかどうかです。(Visitを正確に2つのパラメーター、2つ以下でオーバーロードする必要があります)。

4

1 に答える 1

8

私はあなたのために「トリプル」ディスパッチパターンを作成しました:http://ideone.com/FoXNW それは非常に簡単です。以下の主要部分:

class Derived1;
class Derived2;
class Visitor;
class Base
{
public:
   virtual void Accept(Visitor &iVisitor, Base& param1) = 0;
   virtual void Accept(Visitor &iVisitor, Derived1& param2) = 0;
   virtual void Accept(Visitor &iVisitor, Derived2& param2) = 0;
};

class Visitor
{
public:
    virtual void Visit(Derived1 & param1, Derived1 &param2) { cout << "11\n"; }
    virtual void Visit(Derived1 & param1, Derived2 &param2) { cout << "12\n"; }
    virtual void Visit(Derived2 & param1, Derived1 &param2) { cout << "21\n"; }
    virtual void Visit(Derived2 & param1, Derived2 &param2) { cout << "22\n"; }
};

class Derived1: public Base
{
public:
   virtual void Accept(Visitor &iVisitor, Base& param1) 
   { param1.Accept(iVisitor, *this); }
   virtual void Accept(Visitor &iVisitor, Derived1& param2)
   { iVisitor.Visit(*this, param2); }
   virtual void Accept(Visitor &iVisitor, Derived2& param2)
   { iVisitor.Visit(*this, param2); }
};
class Derived2: public Base
{
public:
   virtual void Accept(Visitor &iVisitor, Base& param1) 
   { param1.Accept(iVisitor, *this); }
   virtual void Accept(Visitor &iVisitor, Derived1& param2)
   { iVisitor.Visit(*this, param2); }
   virtual void Accept(Visitor &iVisitor, Derived2& param2)
   { iVisitor.Visit(*this, param2); }
};

void Visit(Visitor& visitor, Base& param1, Base& param2)
{
   param2.Accept(visitor, param1);
}

Derived1とDerived2の実装は文字通り同じであることに注意してください。より多くの派生物がある場合は、これをマクロで囲むことができます。

于 2012-07-08T22:15:35.647 に答える