c+++構造関数の初期化リスト


まず、下図のC++コードを実行します。出力は何ですか?

class A
{
private:
 int n1;
 int n2;
public:
 A(): n2(0) , n1(n2 + 2)
 {
 }
 void Print()
 {
  cout<<"n1:"<<n1<<",n2:"<<n2<<endl;
 }
};
int main(void)
{
 A a;
 a.Print();
 return 0;
}
答え:出力n 1はランダムな数字で、n 2は0です。C+++において、メンバー変数の初期化順序は、構造関数の初期化リストにおけるこれらの順序とは無関係である変数のタイプ内の宣言順序と同じである。この問題では、まずn 1を初期化しますが、初期n 1のパラメータn 2は初期化されておらず、ランダム値ですので、n 1はランダム値です。n 2を初期化するときは、パラメータ0によって初期化するので、n 2=0です。
コンストラクタの初期化リストは、メンバを初期化するための値だけを指定しています。これらの初期化の実行順序は指定されていません。メンバー初期化の手順はメンバーの順序を定義し、最初のメンバーはまず初期化され、次に第二のメンバーが順次類推される。つまり、C+++コンパイラは構造関数のパラメータリストを入手しやすく、パラメータを取得し、メンバー変数の宣言順にメンバー変数を初期化します。
ここを見ていると面倒臭いかもしれませんが、クラスの中の一つのデータメンバーが他のデータメンバーによって初期化されると、初期化リストの順序はメンバー変数の声明の順序と一致しないといけません。
確かにそうです。だから、初期化リストの操作は全部構造関数の関数の中に入れてデータのメンバーを賦課すればいいという考えがあります。確かにこのようにすればいいです。でも、構造関数の初期化リストは必要です。
一部のデータメンバーはコンストラクション初期化リストで初期化しなければならない。このような構成員に対して,構造関数の体内ではそれらの値付けには役立たない。デフォルトのコンストラクタのクラスタイプのメンバーがいません。また、constタイプのメンバー変数と参照型のメンバー変数は、どのタイプであれ、コンストラクタ初期化リストで初期化されなければなりません。例えば、以下のコンストラクタ定義はエラーである:

class A
{
private:
 int i;
 const int j;
 int &k;
public:
 A(int ii)
 {
  i = ii;
  j = ii;
  k = ii;
 }
};
は、constオブジェクトまたは参照タイプのオブジェクトを初期化することができますが、それらに値を割り当てることはできません。コンストラクタの関数を実行する前に、初期化を完了するには、constまたは参照タイプのデータメンバを初期化する唯一の機会は、コンストラクタの初期化リストにある。例えば、次の構成関数の定義は正しいです。

class A
{
private:
 int i;
 const int j;
 int &k;
public:
 A(int ii) : i(ii) , j(i) , k(ii)
 {
 }

 A() : j(0) , k(i)
 { }
};

int main(void)
{
 A a;
 return 0;
}