我想创建一个碰撞系统,其中一个基类表示场景中的一个对象,实现所有碰撞逻辑,并且当检测到碰撞时,将为程序逻辑调用派生类函数。我面临的问题是,基类需要了解所有派生类,才能使不同功能中的分派正常工作。
例如,基类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 */
}
};
Main函数创建两个对象,并检查它们之间的碰撞。
int main(int argc, char ** argv){
Player * player = new Player();
Fire * fire = new Fire();
fire->Collides(player);
}
最终发生的事情是,从Fire::OnCollisionDetected(BasePhysicsObject * another_object)
调用的Collides()
不会使用派生类作为参数(即Player::OnCollisionDetected(Fire * fire)
)来调用函数,而是调用Player::OnCollisionDetected(BasePhysicsObject * another_object)
再次调用该函数,导致堆栈溢出。
正如我所了解的那样,为了使双重调度正常工作,我需要在基类中为所有派生类声明OnCollisionDetected(Derived *)
,但这是一个令人生畏的解决方案。还有其他方法吗?
答案 0 :(得分:0)
对于双重调度模式,您必须有一个虚拟调度程序。 第一次调度是通过在lhs实例上进行虚拟调用完成的,而与通过rhs实例进行调度相比:
class BasePhysicsObject {
public:
virtual ~BasePhysicsObject() = default;
virtual void CollideDispatcher(BasePhysicsObject* ) = 0;
// The true collision code.
virtual void OnCollisionDetected(Fire*) = 0;
virtual void OnCollisionDetected(Player*) = 0;
};
class Player : public BasePhysicsObject {
public:
// Always same implementation
// but `this` type is different for each class
// Which allow correct overload resolution
void CollideDispatcher(BasePhysicsObject* rhs) override { rhs->OnCollisionDetected(this); }
void OnCollisionDetected(Fire* rhs) override { /* Player/Fire collision */ }
void OnCollisionDetected(Player* rhs) override { /*Player/Player collision*/ }
};
class Fire : public BasePhysicsObject {
public:
// Always same implementation
// but `this` type is different for each class
// Which allow correct overload resolution
void CollideDispatcher(BasePhysicsObject* rhs) override { rhs->OnCollisionDetected(this); }
void OnCollisionDetected(Fire* rhs) override { /* Fire/Fire collision */ }
virtual void OnCollisionDetected(Player* rhs) override {
// Fire/Player collision:
// might be symmetrical to Player/Fire collision and so:
rhs->OnCollisionDetected(this);
}
};