Many people take C++ as the end all be all of languages. And why not? It supports many different paradigms of programming at once: functional, object oriented, templated, metaprogramming, assembly and probably more.

But what doesn’t it support? I don’t mean garbage collection or the other niceties of managed code. I mean at a fundamental language level, what is hard to do in C++?

Calling a function based on the runtime type of an object is easy. You make a virtual method on the super class and override it in each subclass. Then even if all you have is a pointer to the super class, the sub class function gets called.

But what if I want to call a function based on two types of objects?

Yikes, now you’re in for some fun.

Visitor

The Visitor pattern is used to get doubly virtual methods.

As an example:

class Visitor

{

public:

      virtual void visit( ClassA& a) = 0;

      virtual void visit( ClassB& b) = 0;

};

 

class SuperClass

{

public:

      virtual visit( Visitor& visitor ) = 0;

};

 

ClassA::visit( Vistitor& visit )

{

      visitor.visit(*this);

}

 

ClassB::visit( Visitor& visitor )

{

      visitor.visit(*this);

}

“Visitor” is my visitor class, SuperClass is an interface my concrete class inherit from. ClassA and ClassB are my concrete classes.

Now I can do the following:

SuperClass nodes[];

void Operate( Visitor& visitor )

{

      for( int i = 0; i < numNodes; i++ )

            nodes[i]->visit( visitor );

}

Notice how I don’t need to have any more loops than this one to do all my operations. All I need to do is define a new Visitor to do something. Want to print everything out? Call Operate( PrintVisitor() );

Want to add everything up from ClassA but not ClassB? No need for dynamic_casts, just call Operate( AddUpClassAVisitor() ); like so:

class AddUpClassAVisitor : public Visitor

{

public:

      AddUpClassAVisitor() : m_value( 0 ) {}

      void visit( ClassA& a ) { m_value += a.GetValue();

      void visit( ClassB& b ) {} // Don't do anything

      int GetValue() { return value; }

private:

      int m_value;

};

The Visitor pattern allows me to separate out class types from operations. Thus I have two virtual calls, one to the operation I’m doing and one to the class I’m operating on.

The Disadvantages

Wouldn’t it be nice if C++ had some way to do this for you automagically? Imagine if you had to manually setup vtables every time you used inheritance? Well guess what, using the Visitor pattern is a pain if you ever want to add new classes. You have to go to the base Visitor class and add it to the interface. Then you need to go through every single concrete visitor class and update it to account for the new class.

Sucks, doesn’t it? It does have one advantage though: it forces you to consider the new object's effect on all implemented classes. If you had seperate functions for each operation, you may forget to update each function for the new type of class.

But the niceties of Visitor may be worth the pain depending on the problem you’re trying to solve. If you are facing a requirement that you have multiple types of objects and multiple operations to run on each and each operation may need to be customized per object, Visitor is the way to go.