c++classtemplatespointersextending-classes

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


I am currently programming something where I hit this problem:

I have a Scene class and a MainScene class:

class Scene{
    Scene();
}

class MainScene : public Scene{
    MainScene();
}

And what I want to do is keep track of a list of scenes like this:

std::map<std::string, Scene*> scenes;

And I add a scene to it like this:

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

and I have a function like this:

template <class T>
void SceneManager::recreateScene(T* &scene)
{
    scene = new T();
}

So that when I want to use a function loadscene, I can grab the scene from the list and delete the current scene and create the new scene with the function recreateScene. But the map gives me Scene. So when I use recreateScene it calls the constructor of Scene() instead of MainScene(). But I need it to know that the scene in the list is a MainScene so it creates a new MainScene() instead of a new Scene().


Solution

  • One way to do that is to store the creator alongside the pointer. Something like this:

    std::map<std::string, std::pair<Scene*, std::function<Scene*()>> scenes;
    
    scenes.emplace("mainscene", {nullptr, []() { return new MainScene(); }});
    

    Then, modify 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);
    

    Side note: If these pointers own the Scene object, they should not be raw pointers, but std::unique_ptr<Scene> instead. DTTO for the return type of the std::function.