#include <iostream>
#include <vector>
using namespace std;
struct Orc; struct Human;
struct Character_visitor {
virtual void visit(Orc& orc) = 0;
virtual void visit(Human& human) = 0;
};
struct Character {
Character(char *name) : name(name) {}
virtual void accept(Character_visitor& cv) = 0;
char *name;
};
struct Orc : public Character {
Orc(char *name) : Character(name) {}
virtual void accept(Character_visitor& cv) { cv.visit(*this); }
};
struct Human : public Character {
Human(char *name) : Character(name) {}
virtual void accept(Character_visitor& cv) { cv.visit(*this); }
};
class Info_visitor : public Character_visitor {
public:
Info_visitor() : line(0) {}
void visit(Orc& orc) {
cout << ++line << ". Orc: " << orc.name << endl;
}
void visit(Human& human) {
cout << ++line << ". Human: " << human.name << endl;
}
private:
int line; // visitor has state
};
main() {
vector<Character *> characters;
typedef vector<Character *>::iterator ci;
characters.push_back(new Orc("Grok"));
characters.push_back(new Human("Bob"));
characters.push_back(new Orc("Gonk"));
Info_visitor iv;
for(ci i = characters.begin(); i != characters.end(); ++i)
(*i)->accept(iv);
}
The visitable Character classes define the method for traversal. Here, the visitor only visits the objects themselves, but a tree-like hierarchy is easily established.
The fact that the visitor is an class, makes it possible to have a state in the visitor, enabling features such as "killing 1 Orc out of 10" :).