#c #pointers #vector #base-class
Вопрос:
(извините за мой плохой английский)
У меня есть базовый класс с вектором указателей на рисоваемые объекты в нем и методом draw (), который использует данные из этого вектора.
class GameObject
{
protected:
std::vector<Drawable*> drawable;
...
void GameObject::draw() { for (const autoamp; object : drawable) window.draw(*object); }
В производных классах я хочу иметь возможность добавлять некоторые рисоваемые объекты
class Player : public GameObject
{
protected:
RectangleShape shape;
...
Player::Player(float x, float y, float z)
{
shape.setPosition [...]
drawable.push_back(amp;shape);
...
и нарисуйте их, используя метод указателя базового класса
std::vector<GameObject*> gameObjects;
...
for (autoamp; gameObject : gameObjects) gameObject->draw();
Программа выходит из строя (я думаю, потому что базовый класс ничего не знает о векторных данных в производном классе).
Я понимаю, что мог бы сделать этот метод чисто виртуальным и определить его в производных классах, но это не так удобно. Может быть, есть другой способ, более похожий на этот?
upd:
Level::Level()
{
player = Player(500.f, 500.f); //Player player; in header file
gameObjects.push_back(amp;player);
}
void Level::display()
{
for (auto gameObject : gameObjects) gameObject->draw();
}
Комментарии:
1. » Программа выходит из строя (я думаю, потому что базовый класс ничего не знает о векторных данных в производном классе) » — это не проблема. Код выглядит нормально для меня, так что, скорее всего, он выйдет из строя в другом месте кода, который вы не показали. Например, если
GameObject*
указатели вgameObjects
указывают на недопустимые объекты. Вы не показали, какgameObjects
заселяется.2. То, что вы показали до сих пор, будет работать нормально. Однако, если вы когда-либо сделаете копию
Player
объекта,Player::GameObject::drawable
вектор в новой копии по-прежнему будет содержать адресPlayer::shape
в старой копии, что приведет к проблемам. Поэтому обязательно отключите копирование и перемещение объекта при этом.3. @BenVoigt или просто внедрите конструкторы копирования/перемещения
Player
, чтобы добавить новоеshape
вdrawable
вектор, а не староеshape
.4. @RemyLebeau: Это не кажется «простым», если в вектор могут быть добавлены элементы
drawable
на нескольких уровнях иерархии, некоторые из которых, возможно, потребуется глубоко скопировать, некоторые перевести на новый адрес подобъекта, а некоторые оставить в покое (возможно, они относятся к глобальным). Да, можно написать конструктор копирования и перемещения, если эти операции необходимы. Скорее всего, это не так, и они вызываются случайно, что покажет удаление конструктора.5. @RemyLebeau извините, обновлено
Ответ №1:
Проблема в коде, добавленном вашей правкой-похоже, мой хрустальный шар сегодня работает.
Вы создаете временную Player
переменную и перемещаете ее в player
переменную-член. Это заканчивается вектором , содержащим адрес shape
внутри временного Player
, который немедленно уничтожается, оставляя висящий указатель.
Используйте список инициализаторов ctor, чтобы избежать перемещения:
Level::Level()
: player(500.f, 500.f /* where did Z go? */)
{
gameObjects.push_back(amp;player);
}
И отключите операторы присваивания, чтобы предотвратить случайное выполнение этого в других местах:
class Player
{
// ...
Playeramp; operator=(const Playeramp;) = delete;
Playeramp; operator=(Playeramp;amp;) = delete;
};