2011-09-08 3 views
26

コンストラクタチェーンの理解は、クラス内に複数のコンストラクタがある場合(オーバーロードされたコンストラクタ)、そのうちの1つが別のコンストラクタを呼び出そうとした場合、 このプロセスはCONSTRUCTOR CHAINING C++ではサポートされていません。 オンライン資料を読みながら最近、私はC++でのコンストラクタのチェーン

...それはこのように書きます....この段落に出くわしたあなたはあなたが戻って再初期化クラスにメンバ関数を書きたい状況で自分自身を見つけることがデフォルト値に変更します。これを行うコンストラクタをすでに持っている可能性が高いため、メンバ関数からコンストラクタを呼び出そうと思うかもしれません。前述のように、C++ではチェインのコンストラクタ呼び出しは不正です。関数内のコンストラクタからコードをコピーすることができますが、これは機能しますが、重複するコードにつながります。この場合の最良の解決策は、コードをコンストラクタから新しい関数に移動し、コンストラクタに関数を呼び出してデータを初期化する作業をさせることです。

コンストラクタを呼び出すメンバ関数もコンストラクタチェインになりますか? このトピックについては、C++で詳しく説明してください。

+3

私はそうではないと思います。そして、コンストラクタを連想させることはコンストラクタをコールすると思うかもしれないと考えるかもしれないと言った直後に、コンストラクタの連鎖は不正です。値。しかし、誰が知っている、あなたは記事を引用していないか、それがコンストラクタチェーンを記述している箇所を引用しているので、別のところで既に説明したような珍しい意味で使っているかもしれません。 –

+1

違法ではありません。メンバーからコンストラクタを呼び出すと、呼び出しを行う 'this'オブジェクトではなく、構築が適用される一時オブジェクトを作成する効果があります。 –

+1

@Amardeep:コンストラクタの連鎖は「違法」ではなくC++ 03では「不可能」と言う方がより正確でしょう。それを行うことを記述するための構文は存在しません。あなたが言うように、通常の定義によってコンストラクタを呼び出すことは、コンストラクタチェーンと全く同じことではありません。 –

答えて

17

段落...あなたが構築しない限り、コンストラクタを呼び出さないでください、と言って基本的にこれは言う:

class X 
{ 
    void Init(params) {/*common initing code here*/ } 
    X(params1) { Init(someParams); /*custom code*/ } 
    X(params2) { Init(someOtherParams); /*custom code*/ } 
}; 

あなたはどちらかのメンバ関数からのコンストラクタを呼び出すことはできません。あなたがそれをやったことを、あなたに見えるかもしれませんが、それは錯覚だ:

class X 
{ 
public: 
    X(int i):i(i){} 
    void f() 
    { 
     X(3); //this just creates a temprorary - doesn't call the ctor on this instance 
    } 
    int i; 
}; 

int main() 
{ 
    using std::cout; 
    X x(4); 
    cout << x.i << "\n"; //prints 4 
    x.f(); 
    cout << x.i << "\n"; //prints 4 again 
} 
+0

@ Armen ..初めて4を印刷したときに、コンストラクタを実際に呼び出していて、2回目に4を出力したときに、コンストラクタを呼び出すことによって結果が得られたかのように感じますf())、何が起こっているのはそれほどではありません.. !!!それは...ですか ??しかし、私は上記のコードであなたの最初のコメントを理解していない/これはちょうど一時的に作成 - このインスタンス上のctorを呼び出さないでください。もう少し明確に私にそれを説明できますか? – jsp99

+0

これはC++ 11で変更されました。http://stackoverflow.com/a/33275207/1915854を参照してください。 –

3

これはテキストの内容とは異なります。それはあなたのコンストラクタが正常で合法なメンバ関数を呼び出すことを示唆しています。これは明示的にctorを再度呼び出すのを避け、ctorとreset関数の間でコードを重複させないようにするためです。

Foo::Foo() { 
    Init(); 
} 

void Foo::Reset() { 
    Init(); 
} 

void Foo::Init() { 
    // ... do stuff ... 
} 
+0

テキストでは、コンストラクタを呼び出しますが、テキストには "あなたのメンバ関数からコンストラクタを呼び出そうとすると誘惑されるかもしれませんが、前述したように、C++ではコンストラクタ呼び出しの連鎖は不正です。これは、アイデアの混乱によって、著者が、「コンストラクタ呼び出しの連鎖」が、記事がそれを行うことを推奨しているかどうかに関係なく、「メンバー関数からコンストラクタを呼び出す」ことと関係があると考えたことを示唆しています。もちろん、厄介な編集だけかもしれません。 –

+0

"おそらく既にこれを行うコンストラクタがあるので、メンバ関数からコンストラクタを呼び出そうとしたいかもしれません。私は、これは、メンバー関数を呼び出すことは避けるべきであることを意味していると思った.. !! ??? – jsp99

+0

@Appy:必ずしもそうではありません。たとえば、 'Foo' * * this = Foo();というクラスでは、必ずしも最も効率的ではないが、オブジェクトをリセットするには完全に合理的な方法かもしれない。次に、この関数はコンストラクタを呼び出します。単に 'this'を構築するために呼び出されません。 –

0

メンバー関数のコンストラクタを呼び出すかどうかは分かりませんが、悪い習慣です。初期化コードを新しい関数に移動することは論理的な方法です。

基本的に

+0

それは悪い習慣ではない。うまくいかない。 – Johnsyweb

+0

私はJohnsywebに同意します。別のコンストラクタからコンストラクタを呼び出すと、内部に一時的なローカル変数が作成され、コンストラクタが終了すると削除されます。 'this'オブジェクトは、それの影響を受けません。それを行う唯一の方法は、新しいプレースメントであり、C++のFAQは何度も繰り返されています。それは恐ろしいことです。 – MasterMastic

1

我々はメンバ関数からのコンストラクタを呼び出すとき、それはその型のオブジェクトを一時的に作成されます。 派生クラスの関数を呼び出す場合は、関数がスコープから外れると、すべての親コンストラクタも実行され、破棄されます。

これは、すべてのクラスのオブジェクトを作成するため、メンバー関数のコンストラクタを呼び出すための良い方法ではありません。

15

C++ 11では、(部分的に)コンストラクタチェインが可能です。この機能は「delegating constructors」と呼ばれます。だから、C++ 11には、次の

class Foo 
{ 
public: 
    Foo(int a) : Foo() { _a = a; } 
    Foo(char* b) : Foo() { _b = b; } 
    Foo() { _c = 1.5; } 
private: 
    int _a = 0; 
    char* _b = nullptr; 
    double _c; 
}; 

を行うことができますが、別のコンストラクタを呼び出すコンストラクタは、他のメンバを初期化することは許されない厳しい制限があります。ですから、委任コンストラクタで次の操作を行うことはできません。

class Foo 
{ 
public: 
    Foo(int a) : Foo(), _a(a) { } 
    Foo(char* b) : Foo(), _b(b) { } 
    Foo() { _c = 1.5; } 
private: 
    int _a = 0; 
    char* _b = nullptr; 
    double _c; 
}; 

をMSVC++ 2013でコンパイルエラー「C3511を:委任コンストラクタの呼び出しが唯一のメンバー初期化子しなければならない」を与える後者のコード例について。

関連する問題