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 (&v); if (tv) v.visited (*this); } // ... }; class Lexus3000 : public Car { public: void visit (CarVisitor& v) { ILexusVisitor* lv = dynamic_cast (&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"); } };