有一些对象是Drawable
,有些是Movable
。
所有可移动的物体都是可以破坏的。
我将所有可绘制对象存储在名为drawables
的向量中,将可移动对象存储在名为movables
的向量中。我还有矢量ships
和bullets
,它们分别包含Ship
和Bullet
类型的对象。 Ship
和Bullet
都是Movable
这是类的结构:
class Drawable {
public:
void draw();
};
class Movable : public Drawable {
public:
void move();
}
class Ship : public Movable {
public:
Ship();
}
class Bullet : public Movable {
public:
Bullet();
}
向量声明如下:
std::vector<Drawable*> drawables;
std::vector<Movable*> movables;
std::vector<Ship*> ships;
std::vector<Bullet*> bullets;
问题是,每次我创建一个船,我必须在所有向量中添加它,即
drawables.push_back(ship);
movables.push_back(ship);
ships.push_back(ship);
我创建了单独的drawables
和movables
向量,因为我有一个draw()
函数,它调用draw()
向量中所有对象的drawables
方法。同样,我有一个move()
函数,它调用move()
向量中所有对象的movables
方法。
我的问题是,如何更改结构以防止在不同的向量中添加相同的内容。一旦完成目的,我还需要从所有向量中删除对象。
例如,一旦子弹击中某人或移出屏幕,我将不得不在所有三个向量中搜索后从矢量drawables
,movables
和bullets
中删除它。
好像我没有使用正确的方法来存储这些对象。请提出替代方案。
这似乎更像是一个软件工程问题,而不是编码问题。如有必要,请将问题迁移到其他论坛。
假设您正在使用相当现代的编译器,这正是shared_ptr
存在的原因。
问题是您不知道哪个向量拥有该对象,因此您不知道要删除哪个向量。 shared_ptr
为您提供了这个:它管理对象的生命周期,并在对象的最后一次引用被销毁后删除它。
要创建一个新的Ship
,你可以这样做:
auto ship = std::make_shared<Ship>();
drawables.push_back(ship);
movables.push_back(ship);
ships.push_back(ship);
此时ship
有4个引用(每个向量一个,ship
变量本身)。一旦从所有三个向量中删除它并且局部变量超出范围,它将自动删除。
由于所有Movable
,Ship
和Bullet
都是Drawable
,你为什么不制作一个Drawable
项目的矢量并添加所有不同的类?您将只有一个指向所有不同实例的指针,您将只有这些指针的一个向量。然而,这个解决方案可能需要使Drawable
成为一个抽象类。
如果要维护某个类型的所有对象(指向)的容器,您可能需要采用RAII方法。让对象的构造函数添加到容器中,并从中删除析构函数。您还需要确保没有其他任何内容修改容器,因此它应该是您的类的私有(静态)成员,并使用公共方法提供只读访问权限。
更好的是,将此逻辑移动到自己的类中,以便可以重复使用。这也可以让您现有的容器专注于他们目前的工作。他们只需要一个辅助类类型的新数据成员。
为了减轻删除,我会考虑使用list
而不是vector
。此外,可能值得使用reference_wrapper
而不是指针。指针可以具有空值。虽然你可以记录容器没有空指针,但reference_wrapper
传达了这一点,没有额外的文档。
为了帮助您入门,这里是您可以使用的辅助类模板的开始。
template <class T>
class All {
using ListType = std::list< std::reference_wrapper<T> >;
private:
static ListType the_list;
// A list's iterators are rarely invalidated. For a vector, you would
// not store an iterator but instead search when removing from the_list.
typename ListType::iterator list_it;
public:
// Read-only access to the list.
static const ListType & list() { return the_list; }
// Construction
ListAll() : list_it(the_list.end()) {} // If this constructor is needed
explicit ListAll(T & data) : list_it(the_list.insert(the_list.end(), data)) {}
// Destruction
~ListAll() { if ( list_it != the_list.end() ) the_list.erase(list_it); }
// Rule of 5
// You should also define or delete the copy constructor, move constructor,
// copy assignment, and move assignment.
// If you need the default constructor, then you probably want a method like:
//void set(T & data);
};
template <class T>
typename All<T>::ListType All<T>::the_list{};
名字通常很难找到。我根据获取的东西来命名这个模板,例如:All<Movable>::list()
。