如何简洁地比较许多派生 classes 的基础 class 的值并调用它们的函数?

How would one succinctly compare the values of and call the functions of many derived classes' base class?

我有一个 2d 物理引擎,我一直使用 SFML 在 C++ 中进行编程;我已经为所有 SandboxObject 实施了一个粗略的碰撞检测系统( 每种物理对象的基础 class ),但我有一个进退两难的问题。

我计划从 SandboxObject 派生许多不同的 classes,例如 Circles、Rects 等等,但我想要一个检查每个 SandboxObjectroughHitbox 是否与另一个碰撞的方法。

当程序启动时,它会分配内存,比方说,10,000 Circles

int circleCount = 0;//the number of active Circles
constexpr int m_maxNumberOfCircles = 10000;//the greatest number of circles able to be set active
Circle* m_circles = new Circle[m_maxNumberOfCircles];//create an array of circles that aren't active by default

像这样。

并且每次用户 'spawns' 一个新的 Circle,代码运行

(m_circles + circleCount)->setActive();`
circleCount++

Circle没有生命的本质上根本不存在;它们可能有位置和半径,但如果 Circle 未激活,则该信息将 永远不会 使用。

考虑到这一切,我想做的是遍历 所有 SandboxObject 的派生 classes 的不同数组,因为 SandboxObject 是基础 class 实现了粗略的 hitbox 东西,但是因为会有许多不同的派生 classes,我不知道最好的方法。

我尝试过的一种方法(收效甚微)是指向 SandboxObject

SandboxObject* m_primaryObjectPointer = nullptr;

除非有 > 1 SandboxObject 活动,否则此指针将为空;有了它,我尝试使用递增和递减函数来检查它是否可以指向下一个 SandboxObject,但我无法让它正常工作,因为基 class 指针指向派生的 [=58] =] 行为古怪。 :/

我不是在寻找确切的代码实现,只是一种经过验证的方法,可用于处理许多不同派生 class 的基础 class。

让我知道这个问题中是否有任何我应该编辑的内容,或者我是否可以提供更多信息。

在不知道需求的情况下很难回答这个问题,但您可以 sandbox 维护活动对象和非活动对象的两个向量,并使用基础 class 的 unique_ptrs 进行内存管理.

下面的一些代码:

#include <vector>
#include <memory>
#include <iostream>

class sandbox_object {
public:
    virtual void do_something() = 0;
};

class circle : public sandbox_object {
private:
    float x_, y_, radius_;
public:
    circle(float x, float y, float r) :
        x_(x), y_(y), radius_(r)
    {}

    void do_something() override {
        std::cout << "i'm a circle.\n";
    }
};

class triangle : public sandbox_object {
private:
    float x1_, y1_, x2_, y2_, x3_, y3_;
public:
    triangle( float x1, float y1, float x2, float y2, float x3, float y3) :
        x1_(x1), y1_(y1), x2_(x2), y2_(y2), x3_(x3), y3_(y3)
    {}

    void do_something() override {
        std::cout << "i'm a triangle.\n";
    }
};

class sandbox {
    using sandbox_iterator = std::vector<std::unique_ptr<sandbox_object>>::iterator;
private:
    std::vector<std::unique_ptr<sandbox_object>> active_objects_;
    std::vector<std::unique_ptr<sandbox_object>> inactive_objects_;
public:
    void insert_circle(float x, float y, float r) {
        active_objects_.push_back( std::make_unique<circle>(x, y, r) );
    }

    void insert_triangle(float x1, float y1, float x2, float y2, float x3, float y3) {
        active_objects_.push_back( std::make_unique<triangle>(x1,y1,x2,y2,x3,y3));
    }

    sandbox_iterator active_objs_begin() {
        return active_objects_.begin();
    }

    sandbox_iterator active_objs_end() {
        return active_objects_.end();
    }

    void make_inactive(sandbox_iterator iter) {
        std::unique_ptr<sandbox_object> obj = std::move(*iter);
        active_objects_.erase(iter);
        inactive_objects_.push_back(std::move(obj));
    }

};

int main() {
    sandbox sb;

    sb.insert_circle(10.0f, 10.0f, 2.0f);
    sb.insert_triangle(1.0f, 1.0f, 2.0f, 2.0f, 2.0f, 1.0f);
    sb.insert_circle(1.0f, 6.0f, 4.0f);

    sb.make_inactive(sb.active_objs_begin());
    (*sb.active_objs_begin())->do_something(); // this should be the triangle...

    return 0;
}

您的问题是由于您希望在非多态容器上使用多态方法造成的。

SandboxObject* m_primaryObjectPointer 的优点是它允许您以多态方式处理对象:m_primaryObjectPointer -> roughtHitBox() 将工作而不管对象的实际类型是 CircleRectangle , 或 Decagon.

但是使用 m_primaryObjectPointer++ 进行迭代不会像您预期的那样工作:此迭代假定您迭代 SandboxObject 元素数组中的连续对象(即编译器将使用基类型的内存布局计算下一个地址)。

相反,您可以考虑迭代指针的向量(如果您真的想处理额外的内存管理麻烦,也可以是数组)。

vector<SandboxObject*> universe;  
populate(universe); 
for (auto object:unviverse) {
    if (object->isActive()) {
        auto hb = object -> roughtHitBox(); 
        // do something with that hitbox
    }
}

现在管理宇宙中的对象也很痛苦。因此,您可以考虑改用智能指针:

vector<shared_ptr<SandboxObject>> universe;  

(小demo)