如何简洁地比较许多派生 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,例如 Circle
s、Rect
s 等等,但我想要一个检查每个 SandboxObject
的 roughHitbox
是否与另一个碰撞的方法。
当程序启动时,它会分配内存,比方说,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()
将工作而不管对象的实际类型是 Circle
、Rectangle
, 或 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)
我有一个 2d 物理引擎,我一直使用 SFML 在 C++ 中进行编程;我已经为所有 SandboxObject
实施了一个粗略的碰撞检测系统( 每种物理对象的基础 class ),但我有一个进退两难的问题。
我计划从 SandboxObject
派生许多不同的 classes,例如 Circle
s、Rect
s 等等,但我想要一个检查每个 SandboxObject
的 roughHitbox
是否与另一个碰撞的方法。
当程序启动时,它会分配内存,比方说,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()
将工作而不管对象的实际类型是 Circle
、Rectangle
, 或 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)