C++コピー構造関数のいくつかの詳細

8857 ワード

コピーコンストラクタはC++の最も基礎的な概念の一つで、みんなは自分でコピーコンストラクタに対して理解すると思っていますか?まず3つの質問に答えてください.
1.次の関数のうち、コピーコンストラクション関数はどれですか.なぜですか.
 
X::X(const X&);   
  • X::X(X);   

  • X::X(X&, int a=1);   
  • X::X(X&, int a=1, b=2);  

  •  2. 1つのクラスに複数のコピーコンストラクション関数が存在しますか?
    3.次のセグメントの出力結果を書き出し、理由を説明します.もしあなたがすべて間違いなく答えることができるならば、あなたはすでにコピー構造関数に対してかなりの理解を持っています.
     
    #include    
  • #include    

  •   
  • struct X {   

  •   template   
  •   X( T& ) { std::cout << "This is ctor." << std::endl; }   

  •   
  •   template   

  •     X& operator=( T& ) { std::cout << "This is ctor." << std::endl; }   
  • };   

  •   
  • void main() {   

  •   X a(5);   
  •   X b(10.5);   

  •   X c = a;   
  •   c = b;   

  • }  
     
    回答は次のとおりです.
    1.クラスXについて、1つのコンストラクション関数の最初のパラメータが以下のいずれかである:a)X&b)const X&c)volatile X&d)const volatile X&その他のパラメータがデフォルト値を持っていない場合、この関数はコピーコンストラクション関数である. 
     
    X::X(const X&);//コピーコンストラクタ
  • X::X(X&, int=1);//コピーコンストラクタ
  •  2.クラスには1つ以上のコピー構造関数が存在します.
     
    class X {      
  • public:      

  •   X(const X&);      
  •   X(X&);            // OK   

  • };  
    なお、クラスにX&というパラメータのコピーコンストラクタが1つしか存在しない場合、const Xまたはvolatile Xのオブジェクトを使用してコピー初期化を行うことはできない.
     
    class X {   
  • public:   

  •   X();   
  •   X(X&);   

  • };   
  •     

  • const X cx;   
  • X x = cx;    // error   

  • クラスにコピーコンストラクタが定義場合、コンパイラは自動的にデフォルトのコピーコンストラクタを生成します.このデフォルトのパラメータは、X::X(const X&)またはX::X(X&)であり、コンパイラによってコンテキストに基づいてどちらを選択するかが決定される.
    デフォルトのコピーコンストラクション関数の動作は、デフォルトのコピーコンストラクション関数の実行順序が他のユーザ定義コンストラクション関数と同じであり、親クラス後の子クラスの構造を実行する.コピーコンストラクタは、クラスの各データメンバーに対してメンバーコピー(memberwise Copy)の動作を実行する.a)データメンバーがクラスのインスタンスである場合、そのようなコピーコンストラクタが呼び出される.b)データメンバーが配列である場合、配列の各々に対してビット毎のコピーを行う.c)int,doubleなどのデータメンバーが1つの数である場合、システム内に構築された付与演算子を呼び出して付与.
     
    3.コピーコンストラクション関数はメンバー関数のテンプレートから生成することができない. 
     
    struct X {   
  •     template   

  •     X( const T& );    // NOT copy ctor, T can't be X   
  •   

  •     template   
  •     operator=( const T& );  // NOT copy ass't, T can't be X   

  • };   
  •   

  • 理由は簡単で、メンバー関数のテンプレートは言語のルールを変更しません.言語のルールは、プログラムがコピー構造関数を必要とし、宣言しなければ、コンパイラが自動的に生成すると言います.したがって、メンバー関数のテンプレートは、コンパイラがコピー構造関数を生成することを阻止するものではなく、付与演算子の再ロードも同様の規則に従う.(Effective C++3 edition,Item 45参照)
     
    二上記の著者の討論に対して、理解はもっと深くなったが、以下は一般的な標準の実現と注意事項を与える.
    #include "stdafx.h"
    
    #include "stdio.h"
    
    #include <iostream>
    
    #include <string>
    
    
    
    
    
    struct Test1 
    
    {
    
        Test1() { }
    
        Test1(int i) { id = i; }
    
        Test1(const Test1& test)
    
        {
    
            id = test.id;
    
        }
    
        Test1& operator = (const Test1& test)
    
        {
    
            if(this == &test)
    
                return *this;
    
            id = test.id;
    
            return *this;
    
        }
    
        int id;
    
    };
    
    
    
    class Test2
    
    {
    
    public:
    
        Test2(){ m_pChar = NULL;}
    
        Test2(char *pChar) { m_pChar = pChar;}
    
        Test2(int num) 
    
        { 
    
            m_pChar = new char[num];
    
            for(int i = 0; i< num; ++i)
    
                m_pChar[i] = 'a';
    
            m_pChar[num-1] = '\0';
    
        }
    
        Test2(const Test2& test)
    
        {
    
            char *pCharT = m_pChar;
    
    
    
            m_pChar = new char[strlen(test.m_pChar)];
    
            strcpy(m_pChar, test.m_pChar);
    
    
    
            if(!pCharT)
    
                delete []pCharT;
    
        }
    
        Test2& operator = (const Test2& test)
    
        {
    
            if(this == &test)
    
                return *this;
    
    
    
            char *pCharT = m_pChar;
    
            m_pChar = new char[strlen(test.m_pChar)];
    
            strcpy(m_pChar, test.m_pChar);
    
    
    
            if(!pCharT)
    
                delete []pCharT;
    
    
    
            return *this;
    
        }
    
    private:
    
        char *m_pChar;
    
    };
    
    
    
    int main(int argc, char* argv[])
    
    {
    
        const Test1 ts(1); // Test1()
    
        const Test1* p_ts = &ts;
    
        const Test1 ts2(ts); //Test(const Test1& test)
    
        const Test1 ts3 = ts; //Test(const Test1& test)
    
        Test1 ts4; ts4 = ts;  //Test1& operator = (const Test1& test)
    
    
    
        Test2 t(5);
    
        Test2 t2(t);
    
        Test2 t3 = t2;
    
        Test2 t4; t4 = t;
    
        return 0;
    
    }

     
    注意:第1題の第4オプションのコンパイルについてエラーが表示されます.必要でしょうbはint bに変えてやっと合います