You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让函数调用子类Disc的关联函数而非父类Object的函数?

物理引擎碰撞检测多态调用问题解决方案

问题背景

开发学校作业的简单物理引擎,类继承链为Particle → Object → Disc。PhysicsWorld通过Object*列表遍历处理碰撞,全局声明了intersects(Object, Object)和getPenDist(Object, Object)函数,但实际使用Disc实例时,调用的仍是Object版本的函数,而非Disc的重载版本。且无法将这些函数设为Object的成员函数(因为Disc版本的函数参数为Disc,无法覆盖Object的成员函数)。


解决方案1:RTTI类型判断结合重载

适合作业场景,实现简单。核心是通过dynamic_cast判断对象实际类型,调用对应版本的函数。

修改PhysicsWorld.cpp中的resolveCollisions函数:

#include "PhysicsWorld.h"
#include "Disc.h" // 需要引入Disc头文件

void PhysicsWorld::resolveCollisions(float duration) {
    std::vector<Object*>::iterator iter, iter2;

    for (iter = objectList.begin(); iter != objectList.end(); ++iter) {
        for (iter2 = objectList.begin(); iter2 != objectList.end(); ++iter2) {
            if (*iter == *iter2) continue;

            bool collision = false;
            float penDist = 0.0f;

            // 判断两个对象是否都是Disc类型
            Disc* d1 = dynamic_cast<Disc*>(*iter);
            Disc* d2 = dynamic_cast<Disc*>(*iter2);
            
            if (d1 && d2) {
                // 调用Disc版本的碰撞检测函数
                collision = intersects(*d1, *d2);
                penDist = getPenDist(*d1, *d2);
            } else {
                // 调用默认的Object版本函数
                collision = intersects(**iter, **iter2);
                penDist = getPenDist(**iter, **iter2);
            }

            if (collision) {
                // 此处编写碰撞处理逻辑,使用penDist
            }
        }
    }
}

注意:编译时需确保开启RTTI(多数编译器默认开启,如GCC需添加-frtti编译选项)。


解决方案2:双重分发(面向对象优雅实现)

适合后续扩展更多形状(如矩形、三角形)的场景,完全基于虚函数实现多态,无需全局函数。

步骤1:修改Object.h,添加纯虚分发函数

#include <iostream>
#include "./Particle.h"

// 前置声明Disc类,避免循环引用
class Disc;

class Object : public Particle {
public:
    // 核心分发函数:接收任意Object类型的碰撞检测请求
    virtual bool intersectsWith(Object& other) = 0;
    virtual float getPenDistWith(Object& other) = 0;

    // 针对Disc类型的碰撞检测接口,子类需实现
    virtual bool intersectsWith(Disc& other) = 0;
    virtual float getPenDistWith(Disc& other) = 0;
};

// 保留原全局函数作为 fallback(可选)
bool intersects(Object o1, Object o2);
float getPenDist(Object o1, Object o2);

步骤2:修改Disc.h并实现分发函数

#include "./Object.h"

class Disc : public Object {
protected:
    float radius;
public:
    float getRadius() { return radius; }

    // 第一次分发:将请求转发给other的Disc版本函数
    bool intersectsWith(Object& other) override {
        return other.intersectsWith(*this);
    }

    float getPenDistWith(Object& other) override {
        return other.getPenDistWith(*this);
    }

    // 实现Disc与Disc的碰撞检测逻辑
    bool intersectsWith(Disc& other) override {
        return (other.getPosition() - getPosition()).getNorm() < getRadius() + other.getRadius();
    }

    float getPenDistWith(Disc& other) override {
        return -(other.getPosition() - getPosition()).getNorm() + getRadius() + other.getRadius();
    }
};

步骤3:修改PhysicsWorld.cpp的碰撞处理逻辑

#include "PhysicsWorld.h"

void PhysicsWorld::resolveCollisions(float duration) {
    std::vector<Object*>::iterator iter, iter2;

    for (iter = objectList.begin(); iter != objectList.end(); ++iter) {
        for (iter2 = objectList.begin(); iter2 != objectList.end(); ++iter2) {
            if (*iter == *iter2) continue;

            if ((*iter)->intersectsWith(**iter2)) {
                float penDist = (*iter)->getPenDistWith(**iter2);
                // 此处编写碰撞处理逻辑
            }
        }
    }
}

这种方式无需全局函数,后续添加新形状时,只需在Object中新增对应形状的纯虚接口,再在所有子类中实现即可,扩展性极强。


内容的提问来源于stack exchange,提问作者Gabriel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 06:10:40