Question

I have been playing around with various methods of making the Visitor pattern in C++ more dynamic, such that sibling classes don't have to know about each other, and that allows later extension of the visitor hierarchy. I came up with this example based on "More Effective C++" by Scott Meyers:

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;
};

This appears to work as I would expect, printing out "Asteroid collision" when the GameObject passed is an Asteroid, and I can add classes to the hierarchy just by defining a new ABC with a collide() method and extending DynVisitor.

My question is, when I add a new class to the hierarchy, does DynVisitor need to be recompiled?

EDIT: Added the asteroid class... sorry about that.

Était-ce utile?

La solution

All objects can collide with each other, so they still need to be visitors of each other and hence there is no added "dynamism". DynVisitor is a template and thus needs to be in the translation unit and will be recompiled everytime. In fact, in this example, DynVisitor does't give any benefit because the accept() function can call the collide() function instead of the template visit() function.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top