В настоящее время я программирую что-то, где я столкнулся с этой проблемой
у меня есть Scene
класс и MainScene
учебный класс:
class Scene{
Scene();
}
class MainScene : public Scene{
MainScene();
}
И то, что я хочу сделать, это отслеживать список таких сцен:
std::map<std::string, Scene*> scenes;
И я добавляю сцену к этому как это:
MainScene* mainscene; //I do not make it a new because i want my scenemanager to handle that
scenes.emplace("mainscene", mainscene); // add it to the list
и у меня есть такая функция:
template <class T>
void SceneManager::recreateScene(T* &scene)
{
scene = new T();
}
Так что, когда я хочу использовать функцию loadscene
Я могу взять сцену из списка и удалить текущую сцену и создать новую сцену с помощью функции recreateScene
, Но карта дает мне Scene
, Поэтому, когда я использую recreateScene
это вызывает конструктор Scene()
вместо MainScene()
, Но мне нужно знать, что сцена в списке MainScene
так что это создает new MainScene()
вместо new Scene()
,
Один из способов сделать это — сохранить создателя рядом с указателем. Что-то вроде этого:
std::map<std::string, std::pair<Scene*, std::function<Scene*()>> scenes;
scenes.emplace("mainscene", {nullptr, []() { return new MainScene(); }});
Затем измените recreateScene
:
template <class T>
void SceneManager::recreateScene(Scene* &scene, std::function<Scene*()> creator)
{
scene = creator();
}
// called as:
auto& s = scenes["mainscene"];
recreateScene(s.first, s.second);
Примечание: если эти указатели владеют Scene
объект, они не должны быть необработанными указателями, но std::unique_ptr<Scene>
вместо. DTTO для типа возврата std::function
,
Простой и эффективный способ удовлетворить ваши потребности — реализоватьсамостоятельно восстановить«функционировать следующим образом:
class Scene {
virtual ~Scene();
virtual void self_rebuild() = 0;
};
class MainScene : public Scene {
~MainScene();
void self_rebuild() {
this->~MainScene(); // destroy scene (without deallocation)
new(this) MainScene(); // rebuild a MainScene object in place (without reallocation)
}
};
Основным преимуществом этого метода является очистка / восстановление объекта без освобождения / перераспределения. Это совершенно безопасно, пока объект является наиболее производным объектом класса MainScene
,
Ссылка на стандарт (3.8 / 7):
Если по истечении времени жизни объекта и до повторного использования или освобождения хранилища, которое занимал объект, в месте хранения, которое занимал исходный объект, создается новый объект, указатель, указывающий на исходный объект, ссылка, которая ссылка на исходный объект, или имя исходного объекта будет автоматически ссылаться на новый объект и, как только начнется время жизни нового объекта, может использоваться для управления новым объектом, если:
- хранилище для нового объекта точно перекрывает хранилище
место, которое занимал исходный объект, и- новый объект
того же типа, что и исходный объект (игнорируя верхний уровень
cv-квалификаторы) и- тип исходного объекта не
квалифицированный const, и, если тип класса, не содержит
нестатический член данных, тип которого является константным или является ссылкой
тип и- исходный объект был наиболее производным объектом (1.8) из
тип T и новый объект является наиболее производным объектом типа T (что
то есть они не являются подобъектами базового класса).
Как насчет чисто виртуальной функции в вашей сцене, называемой «клон», которая возвращает сцену *? MainScene может иметь что-то вроде Scene* clone() {return new MainScene(*this);}
Я бы предложил, чтобы объекты обрабатывали свое собственное создание в виртуальной функции. Таким образом, вам не нужно отслеживать тип.
class Scene{
Scene();
virtual ~Scene();
virtual Scene* ReCreate() = 0;
}
class MainScene : public Scene{
MainScene();
virtual ~MainScene();
virtual Scene *ReCreate(){
return new MainScene();
}
}
template <class T>
void SceneManager::recreateScene(T* &scene){
Scene *temp = scene;
scene = scene->ReCreate();
delete temp;
}