C++ オブジェクトで、別のコンストラクターまたはメンバー関数からコンストラクターを呼び出すとき (オブジェクトが既に構築された後)、呼び出しているコンストラクターの初期化リストは引き続き実行されますか?
4 に答える
C++11 では、コンストラクターを同じクラス内の別のコンストラクター (例: 1 ) に委譲することができます。
#include <iostream>
struct SomeType {
int number;
SomeType(int new_number) : number(new_number) {}
SomeType() : SomeType(42) {}
};
int main() {
SomeType a;
std::cout << a.number << std::endl;
}
この例では、この委任の後に初期化子リストを持つことは禁止されています。たとえば、前の例を次のように変更します。
SomeType() : SomeType(42), number(0) {}
はエラーです。
質問が「継承関係が与えられた場合、初期化リストはまだ呼び出されますか?」答えはイエスです。
#include <iostream>
struct SomeBase {
SomeBase(int) {}
};
struct SomeType : SomeBase {
int number;
SomeType(int new_number=0) : SomeBase(new_number), number(new_number) {}
};
int main() {
SomeType a;
std::cout << a.number << std::endl;
}
これは問題なく、希望どおりに機能します。
別のコンストラクター内からコンストラクターを直接呼び出すことは合法ではありません。C++ 11 より前の C++ では、コンストラクターの委任も許可されていないため、次のようになります。
#include <iostream>
struct SomeType {
int number;
SomeType(int new_number) : number(new_number) {}
SomeType() {
SomeType::SomeType(0); // Error!
}
};
int main() {
SomeType a;
std::cout << a.number << std::endl;
}
エラーであり、直接表現できません。
次の(質問を書いたときにあなたが念頭に置いていたことだと思います)例はエラーではありませんが、あなたが望むことはしません:
#include <iostream>
struct SomeType {
int number;
SomeType(int new_number) : number(new_number) {}
SomeType() {
SomeType(0);
number = 42;
}
};
int main() {
SomeType a;
std::cout << a.number << std::endl;
}
ここで、パラメーターを持たないコンストラクターは、SomeType の匿名の一時インスタンスを構築します。これは、コンストラクターが最初に呼び出されたインスタンスとはまったく別のインスタンスです。これは完全に合法ですが、おそらく意図したことではありません。これを行うと、注意しないと無限再帰を作成するリスクがあり、そのようなことをしてしまうと、おそらく設計上の問題の良い指標になると思います!
1ウィキペディアのC++11 記事から派生
派生クラスの初期化リストの WITHIN から基本クラスのコンストラクターを呼び出すことを参照していると思います。この場合、BASE クラス コンストラクターが最初に実行され (その初期化子リストを含む)、派生クラスの初期化子リストが呼び出されます。
ご参考までに、基本クラスのコンストラクターは、派生クラスに対して実行される初期化子リストの前に常に呼び出され、基本クラスのコンストラクターへの呼び出しが派生クラスの初期化子リストの中間または末尾に明示的に表示されている場合でも (最初に表示されているかのように)。その理由は、イニシャライザ リストの項目が、コンストラクタ定義のイニシャライザ リストに表示される順序ではなく、クラスのヘッダー ファイルのクラス DECLARATION に表示される順序で実行されるためです。また、基本クラスのコンストラクターは派生で宣言されることはありませんクラス宣言。C++ では、基本クラス コンストラクターは常に派生クラス コンストラクターの前に呼び出される必要があります (基本クラス コンストラクターの呼び出しが派生クラスの初期化子リストに明示的に表示されているかどうかに関係なく)。また、初期化子リストのどこに表示されていてもかまいません。
別のメソッドまたは別のコンストラクターからコンストラクターを明示的に呼び出さないでください。
本当に必要な場合は、代わりに 2 段階の初期化を使用してくださいInit()
。この場合、オブジェクトの構築後に型メソッドを呼び出します。
コンストラクターを明示的に呼び出すことはできません。 new を介して、またはスタック上でオブジェクトを構築することによってのみ呼び出します。ハッキングする方法はありますが (例: 新しい配置)、それを行わずに、2 段階の構築と初期化を使用してください。