3

我目前正在编程遇到这个问题的东西:

我有一个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(). 但我需要它知道列表中的场景是 aMainScene所以它创建 anew MainScene()而不是 a new Scene()

4

4 回答 4

4

一种方法是将创建者存储在指针旁边。像这样的东西:

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

于 2016-10-26T13:25:05.997 回答
1

满足您需求的一种简单有效的方法是通过以下方式实现“自重建”功能:

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 限定的,并且,如果是类类型,则不包含任何类型为 const 限定或引用类型的非静态数据成员,并且
  • 原始对象是 T 类型的最派生对象(1.8),而新对象是 T 类型的最派生对象(也就是说,它们不是基类子对象)。
于 2016-10-26T14:04:23.407 回答
0

场景上的纯虚函数如何,称为“克隆”,它返回一个场景*?MainScene 然后可以有类似的东西Scene* clone() {return new MainScene(*this);}

于 2016-10-26T13:23:28.943 回答
0

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

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;
}
于 2016-10-26T13:35:07.040 回答