c++ 调用存储在基础 class 变量中的扩展 class 的构造函数,而不知道扩展 class

c++ call constructor of extended class stored in base class variable without knowing extended class

我目前正在编写遇到此问题的东西:

我有一个 Scene class 和一个 MainScene class:

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().

你的场景上的纯虚函数如何,称为 "clone" 其中 returns 一个场景*?然后 MainScene 可以有类似 Scene* clone() {return new MainScene(*this);}

的东西

一种方法是将创建者与指针一起存储。像这样:

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>std::function.

的 return 类型的 DTTO

我建议让对象在虚函数中处理它们自己的创建。这样你就不需要跟踪类型了。

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;
}

满足您需求的一种简单有效的方法是按以下方式实现“self-rebuild”功能:

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)
    }
};

这个方法的主要优点是cleanup/rebuild没有deallocation/reallocation的对象。绝对安全,只要对象是classMainScene.

的最派生对象

参考标准(3.8/7):

If, after the lifetime of an object has ended and before the storage which the object occupied is reused or released, a new object is created at the storage location which the original object occupied, a pointer that pointed to the original object, a reference that referred to the original object, or the name of the original object will automatically refer to the new object and, once the lifetime of the new object has started, can be used to manipulate the new object, if:

  • the storage for the new object exactly overlays the storage location which the original object occupied, and
  • the new object is of the same type as the original object (ignoring the top-level cv-qualifiers), and
  • the type of the original object is not const-qualified, and, if a class type, does not contain any non-static data member whose type is const-qualified or a reference type, and
  • the original object was a most derived object (1.8) of type T and the new object is a most derived object of type T (that is, they are not base class subobjects).