継承されたメンバー関数は、その関数がその継承レベルまでのメンバー データがどのように初期化されたかに依存しないという条件で、初期化リストから安全に呼び出すことができます。そして、size()
メンバーデータに依存せず、リテラルを返すだけなので
int size()
{ return 5; }
あなたのコードはどのコンパイラでも動作します。base_size()
したがって、初期化リストに含める必要さえありません
derived() : base_size(), base_implement(size())
この場合。
base_size
ただし、インスタンス変数 (つまり、メンバー データ) を初期化するコンストラクターがある、より現実的な例に切り替えるとbase_size()
、初期化リストに次のように含める方が理にかなっています。
class base_size
{
public:
base_size ()
{ _size = 5; } // initialization
int size()
{ return _size; }
private:
int _size; // instance variable
};
class base_implement
{
public:
base_implement(int s) : _vec(s)
{
cout << "size : " << _vec.size() << endl;
}
private:
vector<float> _vec;
};
class derived :
public base_implement,
public base_size
{
public:
derived() : base_size(), base_implement(size())
{
// crash
}
};
そして、この特定の例ではvector
、サイズを割り当てるための有効な値を受け取っていないため、プログラムがクラッシュします。その理由は、いわゆるbase-specifier-listにある基本クラスの順序です。
public base_implement,
public base_size
オーソリティについて言及すると、これはセクション 12.6.2「ベースとメンバーの初期化」の標準で述べられていることです。
初期化は次の順序で進行します。
- 最初に、以下で説明するように、最も派生したクラスのコンストラクターに対してのみ、仮想基底クラスは、基底クラスの有向非巡回グラフの深さ優先の左から右への走査に現れる順序で初期化されます。 -to-right」は、派生クラス base-specifier-list 内の基本クラス名の出現順序です。
- 次に、直接基底クラスは、base-specifier-list に表示される宣言順に初期化されます(mem-initializer の順序に関係なく)。
- 次に、非静的データ メンバーは、クラス定義で宣言された順序で初期化されます (これも mem-initializer の順序に関係なく)。
- 最後に、コンストラクターの本体が実行されます。
だから交換するなら
public base_implement,
public base_size
と
public base_size,
public base_implement
すべてが適切に初期化され、プログラムはほとんどの標準準拠のコンパイラで正常に実行されます。1 つには、テストしたばかりの MSVC 10.0 で確実です。