【问题标题】:Visitor Pattern in C++ with multiple visitable parameters具有多个可访问参数的 C++ 中的访问者模式
【发布时间】:2012-07-06 15:59:56
【问题描述】:

考虑以下层次结构:

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 方法。

我的问题是:是否存在任何类似的访问者模式解决方案或类似的东西,我可以在这种情况下使用? (我需要用确切的 2 个参数重载 Visit,不超过 2 个)。

【问题讨论】:

  • 您会说您面临的是在 C++ 中模拟 multiple dispatch 吗?
  • @Luc Danton:嗯,我想是的。我知道查找表解决方案,但我试图避免它(我的基类是纯虚拟的,我想保持这种方式)。 dynamic_cast 解决方案有效,但我需要几个这样的控件,因为调度发生在对象对上。无论如何,如果您对这些解决方案有任何建议,请告诉我。我很高兴听到您的意见。
  • VisitorInterfaceMultiple 需要做什么?依次调用两个accept 方法?在传递另一个时调用一个?
  • @Mark B:其实是一种碰撞检测方法。因此应根据参数类型选择正确的碰撞方法。我认为它不能顺序调用两种方法。必须同时评估这两个参数。

标签: c++ visitor-pattern double-dispatch


【解决方案1】:

我为你创建了“三重”调度模式: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 的实现实际上是相同的。如果您有更多派生,您可以将其包含在宏中。

【讨论】:

    猜你喜欢
    • 2022-12-04
    • 1970-01-01
    • 1970-01-01
    • 2012-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多