Visitor Pattern Explanation

So I've read up all the documentation about the Visitor pattern, and I'm still mightily confused. I've taken this example from another SO question, could someone help me understand? For instance when do we use a visitor design pattern? I think I may have understood some of it, but I'm just not able to see the bigger picture. How do I know when I can use it?

class equipmentVisited
{
  virtual void accept(equipmentVisitor* visitor) = 0;
}

class floppyDisk : public equipmentVisited
{
  virtual void accept(equipmentVisitor* visitor);
}

class processor : public equipmentVisited
{
  virtual void accept(equipmentVisitor* visitor);
}

class computer : public equipmentVisited
{
  virtual void accept(equipmentVisitor* visitor);
}

class equipmentVisitor
{
  virtual void visitFloppyDisk(floppyDisk* );
  virtual void visitProcessor(processor* );
  virtual void visitComputer(computer* );
}

// Some additional classes inheriting from equipmentVisitor would be here

equipmentVisited* visited;
equipmentVisitor* visitor;

// Here you initialise visited and visitor in any convenient way

visited->accept(visitor);

Visitor pattern is used to implement double dispatch. In plain words it means that the code that gets executed depends on runtime types of two objects.

When you call a regular virtual function, it is a single dispatch: the piece of code that gets executed depends on the runtime type of a single object, namely, the one the virtual method of which you are calling.

With the visitor pattern, the method that is being called ultimately depends on the type of two objects - the type of the object implementing the equipmentVisitor, and the type of the object on which you call accept (i.e. the equipmentVisited subclass).

There are other ways to implement double dispatch in C++. Item 31 of Scott Meyer's "More Effective C++" treats this subject in depth.


I think the name of the pattern Visitor is quite unfortunate. Instead of the word visitor I would say Functor or Operator and instead of 'visit' I would say 'apply'.

My understanding of visitor pattern is as follows:

In template meta-programming (STL/BOOST) (compile time binding) you can achieve (the orthogonal design) the separations of operations from structures, by the means of function objects (Functors.) For example in

template <class RandomAccessIterator, class Compare>
void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);

the comp is a functor/operator representing 'less than' operation in a very generic way, so you don't have to have many variants of sort function:

For Visitor pattern you want to achieve something similar but in the case of run time (late) binding:

You want to simplify the interface of A, you want to keep possibility for future extensions (new operations working with A) and you want to achieve the stability of interface of A in the case of those extensions.

From the original 'fat' class:

class A
{ 
  public:
    virtual void function_or_operation_1();//this can be implemented in terms of public interface of the other functions
    virtual void function_or_operation_2();
    //..etc

    virtual void function_or_operation_N();
  public:
    //stable public interface, some functions of procedures

  private:
  //....
}

you remove as many function from public interface as possible (as long as they can be implemented in terms of the non-extracted functions of the same public interface ) and represent the operations as the functor objects or objects from a new Functor hierarchy:

You reduce the number of function in the base class A by having very generic interface using forward declared Functor_or_Operator:

 class Functor_or_Operator;
 class A
 {
   public:
     virtual void apply(Functor_or_Operator*);//some generic function operates on this objects from A hierarchy 
   //..etc
   public:
     //stable public interface, some functions

   private: 
     //....
 }

//Now you have N(=3) classes in A hierarchy (A,B,C) and M operations or functions represented by classes in Functor_or_Operator hierarchy You need to implement N*M definitions of how the every operation from Functor_or_Operator works on every class in A hierarchy. The big thing is, you can do it without changing the interface of the class 'A'. The declaration of the class 'A' becomes very stable in the case of the new additions when introducing new operations or functions working with objects of A hierarchy or in case of new derived classes in the A hierarchy. The stability of A (no changes to A) in the presence of additions is important to avoid costly (and sometimes impossible) recompilation of software which includes headers of A on many places.

For every new class in the A hierarchy, you extend the definition of base Functor_or_Operator, You add new implementation files, but you never need to touch the header of base class A (usually interface or abstract class).

  class Functor_or_Operator 
  {
    virtual void apply(A*)=0;
    virtual void apply(B*)=0;
    virtual void apply(C*)=0;
  }

  void A::apply(Functor_or_Operator* f) 
  { f->apply(this);} //you need this only if A is not abstract (it is instantiable)

  class B:public A
  {
    public:
     void apply(Functor_or_Operator* f) { f->apply(this);} //dynamic dispatch , you call polymhorphic Functor f on this object
     //..the rest of B implementation.
  }

  class C:public A
  {
    public:
     void apply(Functor_or_Operator* f) { f->apply(this);} //dynamic dispatch , you call polymorfic Functor f on this object
    //..the rest of C implementation.
  }

  class Functor_or_Operator_1:public Functor_or_Operator
  {
     public:
        //implementations of application of a function represented by Functor_or_Operator_1 on each A,B,C
        void apply(A*) {}//( only if A is instantiable,not an abstract class)
        void apply(B*) {}
        void apply(C*) {}
  }

  class Functor_or_Operator_2:public Functor_or_Operator
  {
    public:
      //implementations of application of a function represented by Functor_or_Operator_2 on each A,B,C
       void apply(A*) {}//( only if A is instantiable,not an abstract class)
       void apply(B*) {}
       void apply(C*) {}
  }