10
struct B { 
  int b1, b2;  
  B(int, int);
};

struct D : B {
  int d1, d2;
// which is technically better ?
  D (int i, int j, int k, int l) : B(i,j), d1(k), d2(l) {} // 1st Base
// or
  D (int i, int j, int k, int l) : d1(k), d2(l), B(i,j) {} // last Base
};

上記は単なる擬似コードです。実際には、基本コンストラクターを呼び出す順序が重要であることを知りたかったのですか?

いずれかのケースによって引き起こされる悪い動作(特にコーナー ケース) はありますか? 私の質問は、コーディング スタイルではなく、より技術的な側面に関するものです。

4

3 に答える 3

18

質問で参照する順序は、「基本コンストラクターを呼び出す順序」ではありません。実際、コンストラクターを呼び出すことはできません。ユーザーはコンストラクターを呼び出すことができません。コンパイラーのみがコンストラクターを呼び出すことができます。

できることは、初期化子を指定することです。この場合 (コンストラクター初期化子リスト) では、より大きなオブジェクトのサブオブジェクトの初期化子を指定しています。これらの初期化子を指定する順序は重要ではありません。コンパイラは、初期化子を指定する順序に関係なく、言語仕様で定義された特定の順序でコンストラクターを呼び出します。基本クラスのコンストラクターは常に最初に (基本クラスがクラス定義にリストされている順序で) 呼び出され、次にメンバー サブオブジェクトのコンストラクターが呼び出されます (再び、これらのメンバーがクラス定義にリストされている順序で)。

(仮想基本クラスに関しては、この規則にはいくつかの特殊性がありますが、ここには含めないことにしました。)

悪い行動については... もちろん、ここには「悪い行動」の可能性があります。初期化の順序がコンストラクター初期化子リストで使用した順序に依存すると仮定すると、コンパイラーがその順序を完全に無視して独自の順序 (宣言) 代わりに。たとえば、このコードの作成者

struct S {
  int b, a;
  S() : a(5), b(a) {}
};

aは最初に初期化され、 frombの初期値を受け取ることを期待するかもしれませんが、実際には は の前に初期化されるため、これは起こりません。5aba

于 2011-06-06T03:58:33.007 に答える
6

順序は明確に定義されています。初期化時の指定方法には依存しません。
基本クラスのコンストラクターBが最初に呼び出され、次にメンバー変数 ( d1& d2) が宣言された順序で呼び出されます。

@Andrey Tの回答のコメントを説明するには。

class MyClass1: public MyClass2, public virtual MyClass3
{


};

基本クラスのコンストラクターを呼び出す順序は、標準によって明確に定義されており、次のようになります。

MyClass3  
MyClass2
MyClass1

仮想 Base クラスMyClass3は Base Class よりも優先されMyClass2ます。

于 2011-06-06T03:55:51.573 に答える
3

初期化リストに表示される順序は重要ではありません。あなたの場合、基本オブジェクトは常に最初に初期化され、その後に d1 と d2 がこの順序で続きます。初期化は、派生順に実行され、メンバーがクラス定義に現れる順序で実行されます。

そうは言っても、通常、初期化リストを初期化の順序で記述するのは良いスタイルと考えられており、これを行わないと警告を発するコンパイラもあります。

于 2011-06-06T03:55:38.503 に答える