🤖📘🍻 Hooray! After 3 years of work, we've finally released a new ebook on design patterns! Check it out »

Visitor Design Pattern in C++: Recovering lost type information

Motivation. "My Component classes do not know that Composites exist. They provide no help for navigating Composites, nor any help for altering the contents of a Composite. This is because I would like the base class (and all its derivatives) to be reusable in contexts that do not require Composites. When given a base class pointer, if I absolutely need to know whether or not it is a Composite, I will use dynamic_cast() to figure this out. In those cases where dynamic_cast() is too expensive, I will use a Visitor."

#include <iostream>
#include <vector>
using namespace std;

class Visitor
{
  public:
    virtual void visit(class Primitive *, class Component*) = 0;
    virtual void visit(class Composite *, Component*) = 0;
};

class Component
{
    int value;
  public:
    Component(int val)
    {
        value = val;
    }
    virtual void traverse()
    {
        cout << value << " ";
    }
    // Having add() here sacrifices safety, but it supports transparency
    // virtual void add( Component* ) { }
    virtual void accept(Visitor &, Component*) = 0;
};

class Primitive: public Component
{
  public:
    Primitive(int val): Component(val){}
     /*virtual*/void accept(Visitor &v, Component *c)
    {
        v.visit(this, c);
    }
};

class Composite: public Component
{
    vector < Component * > children;
  public:
    Composite(int val): Component(val){}
    void add(Component *ele)
    {
        children.push_back(ele);
    }
     /*virtual*/void accept(Visitor &v, Component *c)
    {
        v.visit(this, c);
    }
     /*virtual*/void traverse()
    {
        Component::traverse();
        for (int i = 0; i < children.size(); i++)
          children[i]->traverse();
    }
};

class AddVisitor: public Visitor
{
  public:
     /*virtual*/void visit(Primitive *, Component*)
    {
         /* does not make sense */
    }
     /*virtual*/void visit(Composite *node, Component *c)
    {
        node->add(c);
    }
};

int main()
{
  Component *nodes[3];
  // The type of Composite* is "lost" when the object is assigned to a
  // Component*
  nodes[0] = new Composite(1);
  nodes[1] = new Composite(2);
  nodes[2] = new Composite(3);

  // If add() were in class Component, this would work
  //    nodes[0]->add( nodes[1] );
  // If it is NOT in Component, and only in Composite,  you get the error -
  //    no member function `Component::add(Component *)' defined

  // Instead of sacrificing safety, we use a Visitor to support add()
  AddVisitor addVisitor;
  nodes[0]->accept(addVisitor, nodes[1]);
  nodes[0]->accept(addVisitor, nodes[2]);
  nodes[0]->accept(addVisitor, new Primitive(4));
  nodes[1]->accept(addVisitor, new Primitive(5));
  nodes[1]->accept(addVisitor, new Primitive(6));
  nodes[2]->accept(addVisitor, new Primitive(7));

  for (int i = 0; i < 3; i++)
  {
    nodes[i]->traverse();
    cout << endl;
  }
}

Output

1 2 5 6 3 7 4 
2 5 6 
3 7 

Code examples

More info, diagrams and examples of the Visitor design pattern you can find on our new resource Refactoring.Guru.