5

Consider the following hierarchy:

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);
   }
};

and the visitor class:

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

Usually I use the visitor pattern to achieve double dispatching when the overload method depends on the parameter type, but I have only the pointer to the base class.

For example:

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

I think this is the only way to achieve double dispatching since the dynamic binding of virtual functions should happen only on the object upon which the method is called and not on its parameters (derived types).

Now I encountered a new situation, where I need a sort of Visit method overloading on multiple parameters. Something like this:

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

I cannot use the classical visitor pattern solution because accept method is called on only one of the parameters.

My question is: does exist any similar visitor pattern solution, or something similar, that I could use in this situation? (I need to overload Visit with exact 2 parameters, no more than 2).

Heisenbug
  • 38,762
  • 28
  • 132
  • 190
  • Would you say that what you're faced with is emulating [multiple dispatch](http://en.wikipedia.org/wiki/Multiple_dispatch) in C++? – Luc Danton Jul 06 '12 at 17:12
  • @Luc Danton: well, I think so. I knew about the look-up table solution but I was trying to avoid it (my base class is pure virtual and I would like to keep it that way). The dynamic_cast solution works, but I need several of such controls since the dispatch happens on objects pair. Anyway, if you have any suggestion reguarding those solution, please tell me. I'd be glad to hear your opinion. – Heisenbug Jul 06 '12 at 17:28
  • What does `VisitorInterfaceMultiple` need to do? Call two `accept` methods sequentitally? Call one while passing in the other? – Mark B Jul 06 '12 at 17:39
  • @Mark B: actually it's a collision detection method. So the right collision method should be selected depending on the parameter types. It can't call two method sequentially I think. Both the parameters must be evaluated at the same time. – Heisenbug Jul 06 '12 at 17:42

1 Answers1

8

I created for you "triple" dispatch pattern: http://ideone.com/FoXNW It is quite easy. Main part below:

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);
}

Note that implementation of Derived1 and Derived2 is literally identical. You can enclose this in macro if you have more derived.

PiotrNycz
  • 23,099
  • 7
  • 66
  • 112