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

时间:2016-10-26 13:17:28

标签: c++ class templates pointers extending-classes

我正在编写一些可以解决此问题的内容:

我有一个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()

4 个答案:

答案 0 :(得分: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的返回类型。

答案 1 :(得分: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-qualifiers)和
  •   
  • 原始对象的类型不是   const-qualified,如果是类类型,则不包含任何类型   类型为const限定的非静态数据成员或引用   类型和
  •   
  • 原始对象是一个派生程度最高的对象(1.8)   类型T,新对象是类型为T的最派生对象(即   是的,它们不是基类子对象。)
  •   

答案 2 :(得分:0)

如何在场景中使用纯虚函数,称为“clone”,它返回一个场景*?然后MainScene可以有Scene* clone() {return new MainScene(*this);}

之类的东西

答案 3 :(得分: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;
}