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

如何通过父类Shape访问子类Circle/Square的成员变量?

针对2D物理引擎形状属性访问的解决方案

方法1:虚函数封装碰撞逻辑(推荐方案)

把碰撞检测逻辑封装到各Shape子类中,基类定义纯虚接口,Body只需调用接口即可,无需直接访问子类属性,符合面向对象的开闭原则。

示例代码:

#include <memory>

// 基础2D向量类型
struct Vec2 {
    float x, y;
    float lengthSq() const { return x*x + y*y; }
    Vec2 operator-(const Vec2& other) const { return {x-other.x, y-other.y}; }
};

class Body;

class Shape {
public:
    virtual ~Shape() = default;
    // 纯虚函数:检测与另一个Body的形状是否碰撞
    virtual bool collidesWith(const Body* other) const = 0;
    // 获取所属Body(用于获取位置)
    virtual const Body* getBody() const = 0;

    // 形状类型枚举,用于子类判断对方类型
    enum Type { Circle, Square };
    virtual Type getType() const = 0;
};

class Body {
public:
    Body(std::unique_ptr<Shape> shape, Vec2 pos) 
        : m_shape(std::move(shape)), m_position(pos) {}

    const Vec2& getPosition() const { return m_position; }
    const Shape* getShape() const { return m_shape.get(); }

    // Body的碰撞检测入口
    bool collidesWith(const Body* other) const {
        return m_shape->collidesWith(other);
    }

private:
    std::unique_ptr<Shape> m_shape;
    Vec2 m_position;
};

class Circle : public Shape {
public:
    Circle(float radius, const Body* body) 
        : m_radius(radius), m_body(body) {}

    Type getType() const override { return Circle; }
    const Body* getBody() const override { return m_body; }

    bool collidesWith(const Body* other) const override {
        const Shape* otherShape = other->getShape();
        if (otherShape->getType() == Circle) {
            const Circle* otherCircle = static_cast<const Circle*>(otherShape);
            // 两圆碰撞检测:距离平方 <= 半径和平方
            Vec2 delta = getBody()->getPosition() - other->getPosition();
            float distSq = delta.lengthSq();
            float radiusSum = m_radius + otherCircle->m_radius;
            return distSq <= radiusSum * radiusSum;
        } else if (otherShape->getType() == Square) {
            const Square* otherSquare = static_cast<const Square*>(otherShape);
            // 实现圆与正方形的碰撞逻辑,可直接访问m_radius和otherSquare->m_side_length
            return true; // 替换为实际逻辑
        }
        return false;
    }

    float m_radius;
private:
    const Body* m_body;
};

class Square : public Shape {
public:
    Square(float sideLength, const Body* body) 
        : m_side_length(sideLength), m_body(body) {}

    Type getType() const override { return Square; }
    const Body* getBody() const override { return m_body; }

    bool collidesWith(const Body* other) const override {
        const Shape* otherShape = other->getShape();
        if (otherShape->getType() == Circle) {
            const Circle* otherCircle = static_cast<const Circle*>(otherShape);
            // 实现正方形与圆的碰撞逻辑,访问m_side_length和otherCircle->m_radius
            return true;
        } else if (otherShape->getType() == Square) {
            const Square* otherSquare = static_cast<const Square*>(otherShape);
            // 正方形碰撞检测逻辑
            return true;
        }
        return false;
    }

    float m_side_length;
private:
    const Body* m_body;
};

方法2:动态类型转换(快速实现方案)

如果需要在外部直接访问子类属性,可使用dynamic_cast判断形状类型并转换,适合小型项目快速迭代。

示例代码(Body类的碰撞检测方法):

bool Body::collidesWith(const Body* other) const {
    const Shape* s1 = m_shape.get();
    const Shape* s2 = other->getShape();

    // 圆-圆碰撞
    if (const Circle* c1 = dynamic_cast<const Circle*>(s1)) {
        if (const Circle* c2 = dynamic_cast<const Circle*>(s2)) {
            Vec2 delta = getPosition() - other->getPosition();
            float distSq = delta.lengthSq();
            float radiusSum = c1->m_radius + c2->m_radius;
            return distSq <= radiusSum * radiusSum;
        }
    }

    // 圆-正方形碰撞
    if (const Circle* circle = dynamic_cast<const Circle*>(s1)) {
        if (const Square* square = dynamic_cast<const Square*>(s2)) {
            // 圆与正方形碰撞逻辑,访问circle->m_radius和square->m_side_length
            return true;
        }
    }

    // 正方形-圆碰撞
    if (const Square* square = dynamic_cast<const Square*>(s1)) {
        if (const Circle* circle = dynamic_cast<const Circle*>(s2)) {
            // 复用圆-正方形逻辑或单独实现
            return true;
        }
    }

    // 正方形-正方形碰撞
    if (const Square* sq1 = dynamic_cast<const Square*>(s1)) {
        if (const Square* sq2 = dynamic_cast<const Square*>(s2)) {
            // 正方形碰撞逻辑,访问sq1->m_side_length和sq2->m_side_length
            return true;
        }
    }

    return false;
}

方法3:访问者模式(复杂形状体系方案)

若后续会添加大量形状类型,访问者模式可避免频繁修改碰撞逻辑,将检测逻辑分离到访问者类中。

示例代码:

// 访问者接口
class ShapeVisitor {
public:
    virtual ~ShapeVisitor() = default;
    virtual void visit(const Circle* circle, const Body* other) = 0;
    virtual void visit(const Square* square, const Body* other) = 0;
};

// 碰撞检测访问者
class CollisionChecker : public ShapeVisitor {
public:
    CollisionChecker() : m_result(false) {}
    bool getResult() const { return m_result; }

    void visit(const Circle* circle, const Body* other) override {
        const Shape* otherShape = other->getShape();
        if (const Circle* otherCircle = dynamic_cast<const Circle*>(otherShape)) {
            Vec2 delta = circle->getBody()->getPosition() - other->getPosition();
            float distSq = delta.lengthSq();
            float radiusSum = circle->m_radius + otherCircle->m_radius;
            m_result = distSq <= radiusSum * radiusSum;
        } else if (const Square* otherSquare = dynamic_cast<const Square*>(otherShape)) {
            // 圆-正方形碰撞逻辑
            m_result = true;
        }
    }

    void visit(const Square* square, const Body* other) override {
        const Shape* otherShape = other->getShape();
        if (const Circle* otherCircle = dynamic_cast<const Circle*>(otherShape)) {
            // 正方形-圆碰撞逻辑
            m_result = true;
        } else if (const Square* otherSquare = dynamic_cast<const Square*>(otherShape)) {
            // 正方形-正方形碰撞逻辑
            m_result = true;
        }
    }

private:
    bool m_result;
};

// 修改Shape基类,添加accept方法
class Shape {
public:
    virtual ~Shape() = default;
    virtual void accept(ShapeVisitor& visitor, const Body* other) const = 0;
    virtual const Body* getBody() const = 0;
    enum Type { Circle, Square };
    virtual Type getType() const = 0;
};

// Circle类实现accept
void Circle::accept(ShapeVisitor& visitor, const Body* other) const {
    visitor.visit(this, other);
}

// Square类实现accept
void Square::accept(ShapeVisitor& visitor, const Body* other) const {
    visitor.visit(this, other);
}

// Body的碰撞检测调用
bool Body::collidesWith(const Body* other) const {
    CollisionChecker checker;
    m_shape->accept(checker, other);
    return checker.getResult();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 10:15:21