有些对象是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
中删除。
似乎我没有使用正确的方法来存储这些对象。请提出一个替代方案。
这似乎更像是软件工程问题,而不是编码问题。如有必要,请将问题迁移到其他论坛。
答案 0 :(得分:1)
假设您使用的是相当现代的编译器,这就是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
变量本身)。一旦将其从所有三个向量中删除,并且本地变量超出范围,它将自动删除。
答案 1 :(得分:0)
由于所有Movable
,Ship
和Bullet
都是Drawable
,为什么不只制作一个Drawable
项的向量,然后将所有里面的不同类?您将只有一个指向所有不同实例的指针,而您将只有这些指针的一个向量。但是,此解决方案可能需要将Drawable
设为抽象类。
答案 2 :(得分:0)
如果要维护包含(指向)某种类型的所有对象的容器,则可能需要采用RAII方法。将对象的构造函数添加到容器,然后将析构函数从容器中删除。您还希望确保没有其他修改容器,因此它应该是类的私有(静态)成员,并使用公共方法提供只读访问权限。
更好的是,将此逻辑移到其自己的类中,以便可以重新使用它。这也将使您现有的容器可以专注于当前的工作。他们只需要一个新的helper类类型的数据成员即可。
为了简化删除操作,我考虑使用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()
。