C++メンバー変数初期化リストと変数初期化順序

5472 ワード

一、メンバー変数初期化リスト
他の関数とは異なり、コンストラクション関数には名前、パラメータリスト、関数体のほかに、初期化リストがあり、初期化リストはコロンで始まり、後にカンマで区切られた一連の初期化フィールドがあります.
class foo
{
	public:
	foo(string s, int i):name(s), id(i){} ; //      
	private:
		string name ;int id ;
};

ここでfoo(string s,int i):name(s),id(i){};メンバーのリストを初期化します.
メンバー変数の初期化順序
1、メンバー変数の使用
初期化リスト初期化時、コンストラクション関数
メンバー・リストを初期化する順序は関係なく、
メンバー変数を定義する順序は関連しています.メンバー変数の初期化順序は変数に基づいて
メモリの順序は関係していますが、メモリの順序はコンパイル期間より早く
変数の定義順序によって決定されます.この点はEffectivec++で詳しく紹介されています.
2、初期化リストを使用して初期化しない場合、
コンストラクション関数内で初期化する場合、
メンバー変数のコンストラクション関数の位置に関係します.
3、注意:クラスメンバーは
定義時は初期化できません(静的定数メンバーを除く)
4、注意:クラス内
constメンバー定数とreference
メンバー変数
でなければなりません
コンストラクタ初期化リスト
で初期化
.
5、注意:クラス
staticメンバー変数は、
クラス外初期化.
    
    
    
クラス内のstatic const静的定数メンバーは、定義時に初期化できます.
6、静的変数の初期化順序は
ベースクラスの静的変数を初期化し、次に
その派生クラス.まで
すべての静的変数が初期化されます.ここは注意が必要だ
グローバル変数と静的変数の初期化は順序付けされません.これも理解に難くありませんが、静的変数とグローバル変数は共通のメモリ領域に配置されています.静的変数は「
役割ドメインのグローバル変数.すべての初期化作業が終了するとmain関数が呼び出され、クラスのコンストラクション関数が実行されると、まずベースクラスのメンバー変数が初期化されます. 
変数の初期化順序は次のとおりです.

ベースクラスの静的変数またはグローバル変数
2派生クラスの静的変数またはグローバル変数

ベースクラスのメンバー変数
4派生クラスのメンバー変数
メンバー変数の初期化時のコンストラクション関数の割り当てと初期化リストの違い
一般的にメンバー変数の初期化を行うには、2つの方法があります.1つ目は、コンストラクション関数に値を割り当てることです.
class Point
{
public:
Point(){ _x = 0; _y = 0;};
Point( int x, int y ){ _x = 0; _y = 0; }
private:
int _x, _y;
};

2つ目は初期化リストを使用することです
class Point
{
public:
Point():_x(0),_y(0){};
Point( int x, int y ):_x(x),_y(y){}
private:
int _x, _y;
};

この二つの用法には違いがある.
一、場合によっては初期化リストを使用する必要があります.特にconstと参照データメンバーが初期化された場合.
class Point
{
//                   ,  const        ,     
public:
Point():_x(0),_y(0){};
Point( int x, int y ):_x(x),_y(y){}
//Point(){ _x = 0; _y = 0;}
//Point( int x, int y ){ _x = 0; _y = 0; }
private:
const int _x, _y;
};

二、効率の面から言えば、内蔵タイプや複合タイプでは差は大きくないが、非内蔵データタイプでは差は明らかである.
ポイントクラスに新しいstringタイプのメンバー変数を追加すると
class Point
{
const int _x, _y;
string _name;
}; 

コンストラクション関数内の値の初期化
Point( int x, int y, string name ){ _x = 0; _y = 0; _name = name; }

_name=nameこの式はstringクラスのデフォルトコンストラクション関数を1回呼び出し、Operator=関数を1回呼び出して割り当てます.したがって、2回の関数を呼び出す必要があります:1回の構築、1回の付与
初期化リストで初期化
Point( int x, int y, string name ):_x(x),_y(y), _name(name){}

_nameは、構造関数をコピーして1つの関数で呼び出されたコードのみで初期化を完了します.
単純なstringタイプでも、不要な関数呼び出しは高いコストをもたらします.クラスがますます大きくなり、ますます複雑になるにつれて、それらの構造関数もますます大きくなり、複雑になるにつれて、オブジェクトの作成の代価もますます高くなるので、一般的には初期化リストを使用して初期化することをお勧めします.constと参照メンバーの初期化要件を満たすだけでなく、低効率な初期化データメンバーを避けることができます.
ソース:
初期化リストを使用する理由は2つあります.理由1.このようにしなければなりません.
「C++Primer」では、初期化メンバーのリストを使用する必要があることについて説明しています.一、初期化が必要なデータメンバーがオブジェクトである場合(継承が含まれている場合、親を呼び出すコンストラクション関数を表示することで親データメンバーを初期化します).二、const修飾のクラスメンバーを初期化する必要がある.三、参照メンバーデータを初期化する必要がある.
すなわち、例1、データメンバーはオブジェクトであり、接オブジェクトはパラメータを含む構造関数のみである.
クラスメンバーが1つある場合、それ自体がクラスまたは構造であり、このメンバーにはデフォルトのコンストラクション関数ではなくパラメータ付きコンストラクション関数が1つしかありません.この場合、このクラスメンバーを初期化するには、このクラスメンバーのパラメータ付きコンストラクション関数を呼び出す必要があります.初期化リストがなければ、では、彼は最初のステップを完成できないので、間違いを報告します.
class Test
{
public:
         Test(int x,int y,int z);
private:
         int a;
         int b;
         int c;
};
class MyTest
{
public:
        MyTest():test(1,2,3){}        //   ,               (      ,                       ,        ,        ,       )。
private:
        Test test;            //  
};

Testにはパラメータ付きコンストラクタが表示されているため,コンパイラに依存して無パラメトリックコンストラクタを生成することはできないため,int型データが3つなければTestのオブジェクトを作成することはできない.
       
TestクラスオブジェクトはMyTestのメンバーで、このオブジェクトtestを初期化したいのですが、
メンバーでリストを初期化するしかありません
パラメータをTestクラスコンストラクタに渡す方法はありません
.
例2、オブジェクト参照またはcosnt修飾データメンバーの別のケースは、クラスメンバーにconstオブジェクトが含まれている場合、または参照が含まれている場合、宣言後すぐに初期化するため、メンバー初期化リストを介して初期化する必要があります.コンストラクション関数では、割り当て値が行われます.これは許されない.
次のようになります.
class Test
{
     priate:
          const int a;               //const    
      public:
          Test():a(10){}           //   
};

または
class Test
{
    private:
         int &a;                        //  
    public:
         Test(int a):a(a){}        //   
}

例3、子クラスは親クラスのプライベートメンバーを初期化し、パラメータ初期化リストに呼び出した親クラスの構造関数を表示する必要があります.以下のようにします.
たとえば、
 class child : public foo
     {
     };

fooの構造関数はこう書かれています.
foo (int x)
    {
       a = x;
    }.

childにはchild(int x){foo(x);}と書きます.コンパイルには合格できません.
サブクラス構造関数をchild(int x):foo(x){}と書くだけでよい.
原因2.効率要求:クラスオブジェクトの構造順序表示、構造関数体に入った後、計算を行い、メンバー変数に対する付与操作であり、明らかに、付与と初期化は異なり、効率の違いを体現し、メンバーがクラステーブルを初期化しなければ、クラスは、自分のクラスメンバーに対してそれぞれ暗黙的なデフォルト構造関数の呼び出しと、割り当てオペレータの呼び出しを行い、クラスオブジェクトであれば効率が保証されません.
注意:コンストラクション関数に初期化が必要なデータ・メンバーは、コンストラクション関数のメンバー初期化リストに明示的に表示されるかどうかにかかわらず、そこで初期化が完了し、初期化の順序はクラスで宣言された順序と一致し、リストの前後順序とは関係ありませんので、特に注意してください.両者の順序が一致してこそ、効率と正確性を本当に保証することができる.データテーブルの割り当てを初期化すると、コンストラクション関数が再割り当てされるので、両者の一貫性を保証します.
ソース: