【发布时间】:2018-07-19 23:16:01
【问题描述】:
我想创建一个碰撞系统,其中一个基类代表场景中的一个对象,实现所有的碰撞逻辑,当检测到碰撞时,程序逻辑调用派生类函数。我面临的问题是,基类需要了解所有派生类,以便不同函数中的调度正常工作。
例如,基类,OnCollisionDetected 将被派生类覆盖以处理冲突
#include <iostream>
class BasePhysicsObject {
public:
void Collides(BasePhysicsObject * another_object) {
/* ... */
bool collides = true;
if (collides) this->OnCollisionDetected(another_object);
return;
}
/* Function to be overriden */
virtual void OnCollisionDetected(BasePhysicsObject * another_object) = 0;
};
场景中的两个虚拟类,重写了函数 OnCollisionDetected(BasePhysicsObject * another_object),根据 this 参数将调用分派给适当的函数。
class Fire;
class Player : public BasePhysicsObject {
public:
virtual void OnCollisionDetected(BasePhysicsObject * another_object) {
/* double dispatch to specific implementation */
another_object->OnCollisionDetected(this);
}
virtual void OnCollisionDetected(Fire * fire) {
/* Collision with fire object*/
}
};
class Fire : public BasePhysicsObject {
public:
virtual void OnCollisionDetected(BasePhysicsObject * another_object) {
/* double dispatch to specific implementation */
another_object->OnCollisionDetected(this);
}
virtual void OnCollisionDetected(Player * player) {
/* Collision with player object */
}
};
主函数创建两个对象,并检查它们的碰撞。
int main(int argc, char ** argv){
Player * player = new Player();
Fire * fire = new Fire();
fire->Collides(player);
}
最终发生的事情是,从Collides() 调用的Fire::OnCollisionDetected(BasePhysicsObject * another_object) 不会调用以派生类为参数的函数,即Player::OnCollisionDetected(Fire * fire),而是再次回调函数的Player::OnCollisionDetected(BasePhysicsObject * another_object),导致在堆栈溢出中。
据我了解,为了使双重分派工作,我需要在所有派生类的基类中声明OnCollisionDetected(Derived *),但这是一个令人生畏的解决方案。还有其他方法吗?
【问题讨论】:
-
在我看来像
visitor模式。 -
@NeilButterworth 感谢您的回复,那么如果 then else 是多次调度的答案?
-
要使这种方法起作用,您需要
BasePhysicsObject才能拥有virtual void OnCollisionDetected(Fire *) = 0;和virtual void OnCollisionDetected(Player *) = 0;。事实上,当您调用another_object->OnCollisionDetected(this);时,BasicPhysicsObject具有的唯一 重载是OnCollisionDetected(BasePhysicsObject * another_object)。从不考虑派生类型重载。他们有virtual成员,但不覆盖任何内容。使用override将有助于识别问题。这个问题的一般解决方案是使用访问者。 -
您不能使用具有一组不同参数的后代方法覆盖具有一组参数的虚方法,即使参数类型是相关的。覆盖方法的签名必须与它覆盖的方法完全匹配。只有return values are allowed to be covariant,没有参数。
标签: c++ polymorphism