Visitor Pattern
But, I wouldn't want to have a Node.printType function that prints its type and also recursively traverses its children to print their types.
The visitor pattern does exactly this. Conceptually, it allows for a virtual function to be added to an entire class hierarchy, without having to put the function within the class hierarchy itself. Below is a
#include <iostream>
#include <list>
#include <string>
using namespace std;
class Asteroid;
class MyAsteroid;
class IAsteroidVisitor
{
public:
virtual void visit(Asteroid&) = 0;
virtual void visit(MyAsteroid&) = 0;
};
class Asteroid
{
public:
virtual string getType()
{
return "Asteroid";
}
virtual void accept(IAsteroidVisitor& visitor)
{
visitor.visit(*this);
}
};
class MyAsteroid : public Asteroid
{
public:
string getType() override
{
return "My Asteroid";
}
string doFunkyStuff()
{
return "I do something the normal asteroid can't!";
}
void accept(IAsteroidVisitor& visitor) override
{
visitor.visit(*this);
}
};
class AsteroidList
{
private:
list<Asteroid*> m_pAsteroidList;
public:
AsteroidList()
{
m_pAsteroidList.push_back(new Asteroid());
m_pAsteroidList.push_back(new MyAsteroid());
}
void accept(IAsteroidVisitor& visitor)
{
for (list<Asteroid*>::const_iterator i = m_pAsteroidList.cbegin(); i != m_pAsteroidList.cend(); i++)
{
(*i)->accept(visitor);
}
}
};
class AsteroidPrintVisitor : public IAsteroidVisitor
{
public:
void visit(Asteroid& a) override
{
cout<<a.getType()<<endl;
}
void visit(MyAsteroid &ma) override
{
cout<<ma.getType()<<endl;
cout<<ma.doFunkyStuff()<<endl;
}
};
int main(int argc, char *argv[])
{
AsteroidList al;
AsteroidPrintVisitor p;
al.accept(p);
return 0;
}
Labels: design pattern, double-dispatch