C++のデフォルトのコンストラクタとコンストラクタの初期化リスト

4436 ワード

1、デフォルトのコンストラクタとコンストラクタ
(1)コンストラクション関数:C++クラスの新しいオブジェクトを構築する際に呼び出される関数で、戻りタイプがありません!(「なし」!空ではありません!(void))
(2)デフォルトコンストラクション関数:デフォルトコンストラクション関数は、呼び出し時に表示する必要なく実パラメータに伝達されるコンストラクション関数である.
クラス自体がコンストラクション関数を定義していない場合、パラメータなしで関数体も空のデフォルトコンストラクション関数があります.プログラマがコンストラクション関数を定義している限り、コンパイラはデフォルトのコンストラクション関数を提供しません.
デフォルトのコンストラクション関数を定義するには、パラメータのないコンストラクション関数を定義する方法と、すべてのパラメータにデフォルト値があるコンストラクション関数を定義する方法の2つがあります.
class testClass
{
public:
    testClass();                         /*        */
    testClass(int a, char b);        	 /*      */
    testClass(int a=10,char b='c');      /*        */

private:
    int  m_a;
    char m_b;
};

(3)コンパイラはどのような場合にデフォルトのコンストラクタを生成しますか?
次の場合、コンパイルにはデフォルトのコンストラクション関数を生成する必要があります.
  • クラスのクラスオブジェクトデータメンバーにデフォルトのコンストラクション関数がある場合.
  • クラスのベースクラスにデフォルトのコンストラクション関数がある場合.
  • クラスのベースクラスが虚ベースクラスである場合.
  • クラスに虚関数がある場合.

  • (4)「パラメータなしデフォルトコンストラクタ」と「デフォルトパラメータ付きデフォルトコンストラクタ」が同時に存在しないようにする
    パラメータなしのデフォルトコンストラクタとデフォルトパラメータ付きのデフォルトコンストラクタが同時に存在する場合、コンパイラは二義性を生成し、コンパイルエラーを生成します.
    class Sample {
    public:
        //       
        Sample() {
            // do something
            printf("Sample()");
        }
    
        //       
        Sample(int m = 10) {
            // do something
            printf("Sample(int m = 10)");
        }
    };
    
    
    int main()
    {
        Sample s; // error C2668: “Sample::Sample”:            
    
        return 0;
    }
    

    2、構造関数の初期リスト
    C++クラスのメンバー関数には、クラスのコンストラクション関数の内部で初期化するものと、クラスのコンストラクション関数の初期化リストで初期化するものの2つの初期化があります.初期化と付与は、組み込みタイプのメンバーに大きな違いはありません.非組み込み型メンバー変数の場合、2回の構造を回避するために、クラス構造関数を使用してリストを初期化することを推奨します.
    データ・メンバーの初期化とデータ・メンバーへの付与の意味は何ですか?どんな違いがありますか.
    まず、データ・メンバーをタイプ別に分類し、状況を説明します.
    (1)int,floatなどの組み込みデータ型;複合型(ポインタ,参照)
    メンバー初期化リストとコンストラクション関数で行い、パフォーマンスと結果は同じです.
    (2)ユーザ定義タイプ(クラスタイプ)
    結果は同じですが、性能に大きな違いがあります.クラスタイプのデータメンバーオブジェクトは、関数体に入る前に構築が完了しているため、すなわち、メンバー初期化リストでオブジェクトを構築する作業を行い、コンストラクション関数を呼び出し、関数体に入った後、構築済みのクラスオブジェクトへの付与を行う.また、コピー付与オペレータを呼び出して完了します(指定されていない場合は、コンパイラで指定されたデフォルトのメンバー別付与動作を使用します).したがって、初期化リストを使用する場合は、できるだけ初期化リストを使用できます.
    class Test2
    {
    public:
        Test1 test1 ;
        Test2(Test1 &t1):test1(t1){}    //           test1,              
    }
    

    3、初期化リストのあるコンストラクション関数を使用する必要があります.
    (1)メンバータイプはデフォルトコンストラクタがないクラスです.初期化式が表示されていない場合、コンパイラはメンバータイプのデフォルトコンストラクタを暗黙的に使用し、クラスにデフォルトコンストラクタがない場合、コンパイラがデフォルトコンストラクタを使用しようとすると失敗します.
    class Test1
    {
    public:
        Test1(int a):i(a){}//        
        int i;
    };
    class Test2
    {
    public:
        Test1 test1 ;
        Test2(Test1 &t1)
        {test1 = t1 ;}
    };
    

    Test 2のコンストラクション関数ではtest 1=t 1の行が実際に2つのステップに分かれて実行されるため、上記のコードはコンパイルできません.
    Test 1のデフォルトコンストラクタを呼び出してtest 1を初期化
    Test 1にデフォルトのコンストラクション関数がないため、1は実行できないため、コンパイルエラーが発生します.正しいコードは、付与操作の代わりに初期化リストを使用します.
    class Test1
    {
    public:
        Test1(int a):i(a){}        //        
        int i;
    };
    class Test2
    {
    public:
        Test1 test1 ;
        Test2(int x):test1(x){}    //       
    }
    

    (2)constメンバーまたは参照タイプのメンバー.constオブジェクトまたは参照タイプは初期化のみ可能なため、値を割り当てることはできません.
    #include 
    
    using namespace std;
    
    class A
    {
    public:
    #if 0
    	//                          
    	A(){
    		cout<

    注意:コンストラクション関数がパラメータにデフォルトの実パラメータを提供する場合、実際にはデフォルトのコンストラクション関数も定義されます.
    (3)ベースクラスがデフォルトコンストラクタを宣言していない
    #include 
    
    using namespace std;
    
    class Animal
    {
    public:
    	Animal(int weight,int height):        //           
    	m_weight(weight),m_height(height){
    		cout<

    最も簡単な解決策は、Animalのコンストラクション関数をデフォルトコンストラクション関数として宣言することです:Animal(int weight=0、int height=0);
    4、初期化リストのメンバー初期化順序:
    C++クラスメンバーを初期化する場合は、初期化リストに表示される順序ではなく、宣言された順序で初期化されます.
    class CMyClass {
        CMyClass(int x, int y);
        int m_x;
        int m_y;
    };
     
     CMyClass::CMyClass(int x, int y) : m_y(y), m_x(m_y){
    }
    

    上のコードが最初にm_を作ると思っているかもしれません.y=I、そしてm_x=m_y、最後に同じ値があります.ただしコンパイラはm_を初期化するx、そしてm_yは、このような順序で宣言されているためです.結果はm_xには予測不可能な値があります.2つの方法でそれを回避する方法があります.1つは、常に初期化されることを望む順序でメンバーを宣言することです.2つ目は、初期化リストを使用することを決定した場合、常にメンバーを宣言する順序で羅列することです.これは混同を解消するのに役立ちます.
    可能であれば、可能な限り一部のメンバーを使用して他のメンバーを初期化しないでください.構造関数のパラメータをメンバーの初期値として使用することが望ましいが、メンバーの初期化順序を考慮するよりも利点がある.たとえば、次のように変更できます.
    class CMyClass {
         CMyClass(int x, int y);
         int m_x;
         int m_y;
     };
     
     CMyClass::CMyClass(int x, int y) : m_x(x), m_y(y) {
     }