c++ - 使用派生参数覆盖函数

标签 c++ polymorphism

我想创建一个碰撞系统,其中一个基类代表场景中的一个对象,实现所有的碰撞逻辑,当检测到碰撞时,调用派生类函数进行程序逻辑。我面临的问题是,基类需要了解所有派生类,以便不同函数中的分派(dispatch)能够正常工作。

例子,基类,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 参数将调用分派(dispatch)到适当的函数。

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

最终发生的事情是,从 Collides() 调用的 Fire::OnCollisionDetected(BasePhysicsObject * another_object) 不会调用具有派生类的函数参数即 Player::OnCollisionDetected(Fire * fire),而是 Player::OnCollisionDetected(BasePhysicsObject * another_object) 再次回调该函数,导致堆栈溢出. 据我所知,为了使双重分派(dispatch)工作,我需要在所有派生类的基类中声明 OnCollisionDetected(Derived *),但这是一个令人生畏的解决方案。还有其他方法吗?

最佳答案

对于双重调度模式,你必须有一个虚拟调度程序。 第一次调度是通过 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);
    }
};

关于c++ - 使用派生参数覆盖函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51425626/

相关文章:

c++ - 通过引用传递是否总能避免切片问题?

c++ - 对象的底层类型是如何在运行时确定的?

c++ - 如何简化复杂的 API 访问 (v8)

c++ - 静态鸭子打字与 CRTP

c++ - fork 子进程

C#加密,C++解密。最后几个字节解密失败

java - 使用空数组创建方法

java - 调用父类(super class)方法而不是子类方法

c++ - 从单排序链表 C++ 中删除一个元素

c++ - 子进程中的间歇性文件访问错误