TITLE: the acyclic visitor

For those of you who are not familiar with the visitor
pattern, see the visitor tip under the patterns section
of the cpptips home page at the URL below. You should be
familiar with this pattern before reading on with this tip.

http://www.ses.com/~clarke/TableOfContents.html

This material came from Robert Martin's artical "Acyclic
Visitor" which can be found at his home page below. I
strongly urge you to get the original article for more
details.

http://www.oma.com


Visitor
-------

Here is a snippet of code which shows the basics of the
visitor pattern. The visitor pattern is useful to add
functionality to a class hierarchy without modifying the
hierarchy itself. 

class Element
{
  public:
	void visit (Visitor& v);
	// ...
};

class ElementA : public Element
{
  public:
	void visit (Visitor& v)
	{
		...
		v.visitedA (*this);
	}
	// ...
};

class ElementB : public Element
{
  public:
	void visit (Visitor& v)
	{
		...
		v.visitedB (*this);
	}
	// ...
};

class Visitor
{
  public:
	void visitedA (ElementA&) = 0; 
	void visitedB (ElementB&) = 0; 
};

class SpecialVisitor : public Visitor
{
  public:
	void visitedA (ElementA&) { printf ("A"); }
	void visitedB (ElementB&) { printf ("B"); }
};

The visitor pattern is like an object-oriented switch statement.
When you add new derived Elements, you have to modify the visitor,
hence changing code and causing recompiling of all users of the
visitor. An additional drawback is that you have to implement
the visitedXXX() methods even if there is no real work being
done.

Acyclic Visitor
---------------

By some redesigning, we can avoid most of the major drawbacks
of using the visitor. We do this with multiple inheritance and
with dynamic_cast<> for "cross hierarchy" casting. Here is the
code example.

Cool, heh?


class CarVisitor
{
	// No methods required!
};

class ILexusVisitor
{
  public:
	void visited (Lexus3000&) = 0;
};

class IToyota4RunnerVisitor
{
  public:
	void visited (Toyota4Runner&) = 0;
};


class Car
{
  public:
	void visit (CarVisitor& v);
	// ...
};

class Toyota4Runner : public Car
{
  public:
	void visit (CarVisitor& v)
	{
		IToyota4RunnerVisitor* tv = 
			dynamic_cast<IToyota4RunnerVisitor*> (&v);
		if (tv)
			v.visited (*this);
	}
	// ...
};

class Lexus3000 : public Car
{
  public:
	void visit (CarVisitor& v)
	{
		ILexusVisitor* lv = dynamic_cast<ILexusVisitor*> (&v);
		if (lv)
			v.visited (*this);
	}
	// ...
};

class PrintCarModelName : public CarVisitor,
	public ILexusVisitor, public IToyota4RunnerVisitor
{
  public:
	// ...
	void visited (Toyota4Runner&) { printf ("Toyota4Runner"); }
	void visited (Lexus3000&) { printf ("Lexus3000"); }
};

