13

これは本当に簡単な質問だと思います。次のコードは、私がやろうとしていることを示しています。

class MemberClass {
public:
    MemberClass(int abc){ }
};

class MyClass {
public:
    MemberClass m_class;
    MyClass(int xyz) {
        if(xyz == 42)
            m_class = MemberClass(12);
        else
            m_class = MemberClass(32);
    }
};

m_classこれは、空のコンストラクター (存在しない) で作成されているため、コンパイルされません。これを行う正しい方法は何ですか?私の推測では、ポインターを使用して を使用してインスタンス化m_classしていますnewが、もっと簡単な方法があることを願っています。

編集:前に言ったはずですが、実際の問題にはさらに複雑な問題があります。環境をセットアップするために、m_class を初期化する前にメソッドを呼び出す必要があります。そう:

class MyClass {
public:
    MemberClass m_class;
    MyClass(int xyz) {
        do_something(); // this must happen before m_class is created
        if(xyz == 42)
            m_class = MemberClass(12);
        else
            m_class = MemberClass(32);
    }
};

ファンシーな初期化リストのトリックでこれを達成することは可能ですか?

4

6 に答える 6

27

条件演算子を使用します。式が大きい場合は、関数を使用します

class MyClass {
public:
    MemberClass m_class;
    MyClass(int xyz) : m_class(xyz == 42 ? 12 : 32) {

    }
};

class MyClass {
    static int classInit(int n) { ... }
public:
    MemberClass m_class;
    MyClass(int xyz) : m_class(classInit(xyz)) {

    }
};

m_class を初期化する前に関数を呼び出すには、そのメンバーの前に構造体を配置し、RAII を活用します。

class MyClass {
    static int classInit(int n) { ... }
    struct EnvironmentInitializer {
        EnvironmentInitializer() {
            do_something();
        }
    } env_initializer;
public:
    MemberClass m_class;
    MyClass(int xyz) : m_class(classInit(xyz)) {

    }
};

これはdo_something()、初期化する前に呼び出されますm_classMyClassコンストラクターの初期化リストが完了する前に、非静的メンバー関数を呼び出すことは許可されていないことに注意してください。関数はその基本クラスのメンバーである必要があり、それが機能するには基本クラスの ctor が既に完了している必要があります。

もちろん、この関数は、作成された最初のオブジェクトだけでなく、作成された個別のオブジェクトごとに常に呼び出されることに注意してください。それを行いたい場合は、初期化子のコンストラクター内で静的変数を作成できます。

class MyClass {
    static int classInit(int n) { ... }
    struct EnvironmentInitializer {
        EnvironmentInitializer() {
            static int only_once = (do_something(), 0);
        }
    } env_initializer;
public:
    MemberClass m_class;
    MyClass(int xyz) : m_class(classInit(xyz)) {

    }
};

コンマ演算子を使用しています。do_somethingfunction-try ブロックを使用して、スローされた例外をキャッチできることに注意してください。

class MyClass {
    static int classInit(int n) { ... }
    struct EnvironmentInitializer {
        EnvironmentInitializer() {
            static int only_once = (do_something(), 0);
        }
    } env_initializer;
public:
    MemberClass m_class;
    MyClass(int xyz) try : m_class(classInit(xyz)) {

    } catch(...) { /* handle exception */ }
};

オブジェクトの作成に失敗する原因do_somethingとなった例外がスローされた場合、関数は次回再び呼び出されます。MyClassお役に立てれば :)

于 2009-06-18T18:57:10.377 に答える
5

初期化リストの構文を使用します。

class MyClass {
public:
    MemberClass m_class;
    MyClass(int xyz) : m_class(xyz == 42 ? MemberClass(12) : MemberClass(32)
                               /* see the comments, cleaner as xyz == 42 ? 12 : 32*/)
    { }
};

おそらく工場でよりきれいになります:

MemberClass create_member(int x){
   if(xyz == 42)
     return MemberClass(12);
    // ...
}

//...
 MyClass(int xyz) : m_class(create_member(xyz))
于 2009-06-18T18:55:40.410 に答える
5
 MyClass(int xyz) : m_class(xyz==42 ? 12 : 32) {}

修正された質問に答えるには、少し注意が必要です。最も簡単な方法はm_class、ポインターを作成することです。本当にデータ メンバーとして使用する場合は、工夫が必要です。新しいクラスを作成します (MyClass の内部で定義するのが最適です)。ctor を呼び出す必要がある関数にします。データ メンバーの宣言の最初に含めます (これにより、最初にインスタンス化されます)

class MyClass 
{
     class initer { public: initer() {
                    // this must happen before m_class is created
                    do_something();                        
                    }
                   }

    initer     dummy;
public:

    MemberClass m_class;
    MyClass(int xyz) : m_class(xyz==42? 12 : 43)
    {
        // dummy silently default ctor'ed before m_class.
    }
};
于 2009-06-18T18:56:26.493 に答える
0

または:

class MemberClass {
public:
    MemberClass(int abc){ }
};

class MyClass {
public:
    MemberClass* m_class;
    MyClass(int xyz) {
        if(xyz == 42)
            m_class = new MemberClass(12);
        else
            m_class = new MemberClass(32);
    }
};

どういうわけか同じ構文を維持したい場合。ただし、メンバーの初期化はより効率的です。

于 2009-06-18T18:59:44.227 に答える
0

これを試して:

class MemberClass
{
public:    
   MemberClass(int abc = 0){ }
};

これにより、デフォルト値とデフォルトのコンストラクターが与えられます。

于 2009-06-18T19:03:13.753 に答える
0

他のことが起こった後に初期化を行うには、実際には次のようなポインターを使用する必要があります。

class MyClass {
public:
    MemberClass * m_pClass;
    MyClass(int xyz) {
        do_something(); // this must happen before m_class is created
        if(xyz == 42)
            m_pClass = new MemberClass(12);
        else
            m_pClass = new MemberClass(32);
    }
};

m_pClass->counter唯一の違いは、メンバー変数に ,の代わりにm_class.counter、およびdelete m_pClassデストラクタでアクセスする必要があることです。

于 2009-06-18T19:23:16.213 に答える