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