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()MainScenenew MainScene()new Scene()

4

4 に答える 4

4

これを行う 1 つの方法は、クリエーターをポインターと一緒に保存することです。このようなもの:

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

この方法の主な利点は、割り当て解除/再割り当てなしでオブジェクトをクリーンアップ/再構築できることです。オブジェクトが class の最も派生したオブジェクトである限り、完全に安全MainSceneです。

標準への参照 (3.8/7) :

オブジェクトの有効期間が終了した後、オブジェクトが占有していたストレージが再利用または解放される前に、元のオブジェクトが占有していたストレージの場所に新しいオブジェクトが作成された場合、元のオブジェクトを指すポインタ、その参照元のオブジェクトを参照するか、元のオブジェクトの名前が自動的に新しいオブジェクトを参照し、新しいオブジェクトの有効期間が開始されると、次の場合に新しいオブジェクトを操作するために使用できます。

  • 新しいオブジェクトのストレージは、元のオブジェクトが占めていたストレージの場所を正確にオーバーレイします。
  • 新しいオブジェクトが元のオブジェクトと同じ型である (最上位の cv 修飾子を無視する)、および
  • 元のオブジェクトの型が const 修飾されておらず、クラス型の場合は、型が const 修飾されているか参照型である非静的データ メンバーが含まれていない。
  • 元のオブジェクトは型 T の最派生オブジェクト (1.8) であり、新しいオブジェクトは型 T の最派生オブジェクトです (つまり、それらは基本クラスのサブオブジェクトではありません)。
于 2016-10-26T14:04:23.407 に答える
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 に答える
0

シーン * を返す「クローン」と呼ばれる、シーンの純粋な仮想関数はどうですか? MainScene は次のようなものを持つことができますScene* clone() {return new MainScene(*this);}

于 2016-10-26T13:23:28.943 に答える