这个模板访问者真的是动态的吗?
我一直在尝试各种方法来使 C++ 中的访问者模式更加动态,这样兄弟类就不必相互了解,并且允许以后扩展访问者层次结构。我根据 Scott Meyers 的“更有效的 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;
};
这似乎按我的预期工作,当传递的游戏对象是小行星时打印出“小行星碰撞”,并且我可以通过以下方式将类添加到层次结构中:使用 collide() 方法定义新的 ABC 并扩展 DynVisitor。
我的问题是,当我向层次结构中添加新类时,DynVisitor 是否需要重新编译?
编辑:添加了小行星类别......对此感到抱歉。
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
所有对象都可以相互碰撞,因此它们仍然需要成为彼此的访问者,因此没有添加“动态”。 DynVisitor 是一个模板,因此需要位于翻译单元中,并且每次都会重新编译。事实上,在这个例子中,DynVisitor并没有带来任何好处,因为accept()函数可以调用collide()函数而不是模板visit()函数。
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.