0

型マップを持つ、クラス Central のプライベート静的メンバー変数があります。このマップに、「 Base 」から派生したクラスのインスタンスを指す「 Base* 」ポインターを設定したいと考えています。派生クラスのこれらのインスタンスは、動的メモリに格納する必要があります。テンプレートの楽しみも少しあります。マップにデータを入力する方法を試しましたが、コンパイル エラーが発生しました (これについては後で説明します)。

わかりやすくするためのコード スニペットを次に示します。

#include <all_necesary_std_headers>

class Base
{
    /* guts */
};

template<class CType>
class Derived: public Base
{
    /* innards */
};

class Central
{
    /* partial entrails */
private:
    // the static map I was referring to
    static std::map<string, Base*> base_map;
};

// Initializing the static map here
std::map<string, Base*> Central::base_map;

class Test1
{
    /* viscera */
};

// Compilation error here, on next line of code.
Central::base_map["Test1"] = dynamic_cast<Base*>( new Derived<Test1>);

class Test2
{
    /* bowels */
};

// Compilation error here, on next line of code.
Central::base_map["Test2"] = dynamic_cast<Base*>( new Derived<Test2>);

これは私が得るコンパイル エラーです :

マップによって割り当てられたメモリを解放するデストラクタが既にあるので、思い出させる必要はありません。main() でクラス " Central " を使用したい。このクラス構造は、ファイルに保存されているクラス名からクラスの新しいインスタンスを動的に作成するために使用されます。

明確であることを願っています。不明な点があれば教えてください。

4

2 に答える 2

2

割り当てステートメントは、名前空間のスコープではなく、関数内でのみ使用できます。

C++11 では、宣言でマップを初期化できます。

std::map<string, Base*> Central::base_map = {
    {"Test1", new Derived<Test1>},
    {"Test2", new Derived<Test2>}
};

過去に行き詰まっている場合は、関数を使用してマップを作成する必要があります。おそらく次のようなもの:

std::map<string, Base*> make_base_map() {
    std::map<string, Base*> map;
    map["Test1"] = new Derived<Test1>;
    map["Test2"] = new Derived<Test2>;
    return map;
}

std::map<string, Base*> Central::base_map = make_base_map();

dynamic_castまた、これらの型がポリモーフィックでない限り (つまりBase、少なくとも 1 つの仮想関数を持っていなければ)使用できないことに注意してください。私の例で行ったように、キャストなしで変換できDerived<T>*ます。Base*ただし、元に戻す必要がある場合はdynamic_cast、それらがポリモーフィックであることを確認する必要があります。

更新: クラスの実装ファイルにのみコードを追加して各クラスを個別に登録できるようにする場合は、クラスをコンストラクターに登録する静的オブジェクトを宣言する必要があります。ここで、初期化順序の大失敗に遭遇します。静的オブジェクトが異なる翻訳単位で初期化される場合、初期化順序が指定されていないため、別のコンストラクタから一方に安全にアクセスすることはできません。

これを修正するには、マップをローカルの静的変数にし、最初にアクセスしたときに初期化します。

static std::map<string, Base*> & base_map() {
    static std::map<string, Base*> map;
    return map;
}

これで、クラスを登録するクラスを定義できます。

template <typename T>
struct BaseMapEntry {
    explicit BaseMapEntry(string name) {
        base_map()[name] = new Derived<T>;
    }
};

そして、それを各クラスに使用します。

// header file
class Test1
{
    static BaseMapEntry<Test1> entry;
    /* gubbins */
};

// source file
BaseMapEntry<Test1> Test1::entry("Test1");

(代わりに、静的メンバーではなく、ソース ファイル内の静的な名前空間スコープ オブジェクトにすることもできます。選択は主に審美的なものです。残念ながら、One Definition Rule により、何をするにしても、ソース ファイル内で定義する必要があります。 .)

于 2013-01-23T12:59:14.393 に答える
0

次の行を使用して、(メンバー関数または ctor から) マップに新しい値を追加します。

Central::base_map["Test1"] = new Derived<Test1>();

boost::assign初期化、使用、またはC++ 11でいくつかの値を入力したい場合:

std::map<string, Base*> Central::base_map = { 
  {"Test1", new Derived<Test1>()}, 
  {"Test2", new Derived<Test2>()} 
};
于 2013-01-23T12:53:29.220 に答える