Я играл с различными методами, чтобы сделать шаблон Visitor в C ++ более динамичным, чтобы классы-братья не должны были знать друг о друге, и это позволяет позднее расширять иерархию посетителей. Я придумал этот пример, основанный на «Более эффективном C ++» Скотта Мейерса:
class Dummy
{
public:
void collide(int& gameobject) { }
};
class DynVisitor
{
public:
template<class Visitor=Dummy, class Arg=int>
void visit(Arg& target)
{
Visitor* vis = dynamic_cast<Visitor*>(this);
if(vis != nullptr)
{
vis->collide(target);
}
else
{
cerr<<"No implementation!"<<endl;
}
}
virtual ~DynVisitor() { }
};
class GameObject
{
public:
virtual ~GameObject() { }
virtual void collide(GameObject& obj)
{
cout<<"Default collide implementation"<<endl;
}
virtual void accept(DynVisitor* vis) = 0;
};
class AsteroidVisitor
{
public:
virtual void collide(Asteroid& target) = 0;
virtual ~AsteroidVisitor() = 0;
};
class Collider : public DynVisitor, public AsteroidVisitor
{
public:
virtual void collide(Satellite& target) { cout<<"Satellite collision."<<endl; }
virtual void collide(Spaceship& target) { cout<<"Spaceship collision."<<endl; }
virtual void collide(Asteroid& target) { cout<<"Asteroid collision."<<endl; }
virtual ~Collider() { }
};
class Asteroid : public GameObject
{
public:
virtual void accept(DynVisitor* visitor)
{
visitor->visit<AsteroidVisitor, Asteroid>(*this);
}
};
int main(int argc, char** argv)
{
DynVisitor* coll = new Collider();
GameObject* ast = new Asteroid();
ast->accept(coll);
delete ast;
delete coll;
return 0;
};
Похоже, это работает, как и следовало ожидать, распечатывая «Столкновение астероидов», когда переданный GameObject является астероидом, и я могу добавить классы в иерархию, просто определив новый ABC с помощью метода collide () и расширив DynVisitor.
У меня вопрос: когда я добавляю новый класс в иерархию, нужно ли перекомпилировать DynVisitor?
РЕДАКТИРОВАТЬ: Добавлен класс астероидов ... извините за это.