Полиморфизм в C++ с вектором с базовыми классами и reference_wrapper
Мне нужно использовать полиморфизм в C++ для объектов, которые хранятся в векторе.
Из других вопросов следует понимать, что объекты в векторе необходимо сохранять по ссылке, так как в противном случае происходит разрезание объектов.
Насколько я понимаю, std::reference_wrapper подойдет, но у меня возникли некоторые проблемы с его реализацией.
ActorRecordingItem является базовым классом, а ActorVehicleEnterRecordingItem является примером класса, который нуждается в полиморфизме (наследуется от ActorRecordingItem через ActorVehicleRecordingItem)
class ActorRecordingItem {
protected:
DWORD m_ticksAfterRecordStart;
Ped m_actorPed;
Vector3 m_location;
DWORD m_ticksDeltaCheckCompletion;
public:
ActorRecordingItem(DWORD ticksStart, Ped actorPed, Vector3 location);
virtual void executeNativesForRecording(Actor actor);
virtual bool isRecordingItemCompleted(Actor actor, Vector3 location);
virtual std::string toString();
};
class ActorVehicleEnterRecordingItem : public ActorVehicleRecordingItem {
protected:
int m_vehicleSeat;
float m_enterVehicleSpeed;
public:
ActorVehicleEnterRecordingItem(DWORD ticksStart, Ped actor, Vector3 location, Vehicle veh, int vehicleSeat,float enterVehicleSpeed);
std::string toString() override;
void executeNativesForRecording(Actor actor) override;
bool isRecordingItemCompleted(Actor actor, Vector3 location) override;
};
Вектор с объектами, которым требуется полиморфизм, хранится в другом классе Actor. В настоящее время он определяется как
class Actor
{
private:
std::vector<std::reference_wrapper<ActorRecordingItem>> m_actorRecordingItems;
public:
Actor();
Actor(Ped ped);
void setRecording(std::vector<std::reference_wrapper<ActorRecordingItem>> actorRecordingItems);
std::vector<std::reference_wrapper<ActorRecordingItem>> getRecording();
std::reference_wrapper<ActorRecordingItem> getRecordingAt(int index);
};
С внедрением ключевых методов как
void Actor::setRecording(std::vector<std::reference_wrapper<ActorRecordingItem>> actorRecordingItems)
{
m_actorRecordingItems = actorRecordingItems;
}
std::vector<std::reference_wrapper<ActorRecordingItem>> Actor::getRecording()
{
return m_actorRecordingItems;
}
std::reference_wrapper<ActorRecordingItem> Actor::getRecordingAt(int index)
{
return m_actorRecordingItems[index];
}
Элементы actorRecordingItems создаются в отдельном методе и присваиваются субъекту. Это делается через
std::vector<std::reference_wrapper<ActorRecordingItem>> actorRecording;
actorRecording.reserve(1000);
ActorVehicleEnterRecordingItem recordingItem(ticksSinceStart, actorPed, actorLocation, actorVeh, seat, enterSpeed );
actorRecording.push_back(recordingItem);
actor.setRecording(actorRecording);
Наконец, это место, где я хочу использовать их и требовать полиморфизма.
std::reference_wrapper<ActorRecordingItem> recordingItem = actor.getRecordingAt(recordingPlayback.getRecordedItemIndex());
recordingItem.get().executeNativesForRecording(actor);
Последняя строка вызывает сбой программы. Я действительно немного растерялся, когда начать изучать эту проблему, поэтому любая помощь будет высоко ценится.
PS извините за очень длинный вопрос:)
1 ответ
Проблема в этих строках:
ActorVehicleEnterRecordingItem recordingItem(ticksSinceStart, actorPed, actorLocation, actorVeh, seat, enterSpeed );
actorRecording.push_back(recordingItem);
Здесь происходит то, что вы создаете локальную переменную и помещаете ссылку на локальную переменную в вектор. Ссылка становится недействительной, как только переменная recordingItem
выходит за рамки. std::reference_wrapper
это именно то, что говорится в названии - это обертка для ссылки, и она не осуществляет какого-либо управления ресурсами. Вы можете обойти эту проблему, имея вектор std::unique_ptr
, std::shared_ptr
или если вы хотите избежать динамического выделения для каждого элемента - boost::variant<>
(в этом случае вам нужно будет указать все потенциальные типы, которые могут быть в векторе).