Copy Constructor

Class の実体をコピーした時に呼ばれる Copy Constructor の説明です。

前田稔の超初心者のプログラム入門

プログラムの説明

  1. このページで説明する Object Class の使い方は、余りお勧め出来ません。
    Class は new で生成して、パラメータで渡すときはポインタを使う方法をお勧めします。
  2. まずソースプログラムと実行結果を見て頂きましょう。
    NameCls の Constructor では、name の領域と age の領域を new でアロケートして、初期値でクリアしています。
    Constructor でアロケートした領域は Destructor で開放します。
    ここまではごく普通の Object Class です。
    /*★ Copy Constructor    前田 稔 ★*/
    #include <iostream>
    #include <string.h>
    using namespace std;
    
    class  NameCls
    {
      public:
        char    *name;
        int     *age;
    
        NameCls()
        {   cout << "Constructor の呼出し\n";
            name= new char[80];
            strcpy(name,"未設定");
            age= new int;
            *age= 0;
        }
        //Destructor
        ~NameCls()
        {
            cout << "Destructor の呼出し\n";
            delete [] name;
            delete  age;
        }
    };
    
  3. main() では Object Class を直接定義して、name と age に値を格納しています。
    問題は Func(cls); の呼び出しです。
    このように Object Class の実体をパラメータで渡すと、NameCls cls のコピーが作成されて Func() に渡されます。
    cls をコピーする時 Constructor を実行すると name と age が失われるので、言語の仕様上から実行しないようになっています。
    Func() 関数では Class を受け取って name と age を表示します。
    //Class の実体をパラメータで受け取る
    void  Func(NameCls obj)
    {
        cout << obj.name << *obj.age << "\n";
    }
    
    int main()
    {
        NameCls cls;
        strcpy(cls.name,"田中一郎");
        *cls.age= 19;
        Func(cls);
        cout << "Func から戻る\n";
        cout << cls.name << *cls.age << "\n";
        return 0;
    }
    
  4. このプログラムの実行結果です。
    Constructor は一度しか呼ばれていないのに、Destructor は二度呼ばれています。
    最初は Func() 関数が終了するときで、二度目は main() 関数が終了するときです。
    また Func() 関数から戻ってから表示すると name と age が壊れています。
    これは Func() 関数の終了時に Destructor が呼ばれ、領域が開放された為です。
    Constructor の呼出し
    田中一郎19
    Destructor の呼出し
    Func から戻る
    ・188
    Destructor の呼出し
    
  5. このようなケースでは Class がコピーされたときに実行される Copy Constructor を定義します。
    Class をコピーするときに呼び出される Copy Constructor です。
    Constructor のパラメータにキーワード const を付けて NameCls &obj を受け取ります。
    そして領域をアロケートして、渡された obj の値をコピーします。
    通常の Constructor と比べてみて下さい。
    Copy Constructor を追加して、先のプログラムが正常に実行される事を確かめて下さい。
        NameCls(const NameCls &obj)
        {   cout << "Copy Constructor の呼出し\n";
            name= new char[80];
            strcpy(name,obj.name);
            age= new int;
            *age= *obj.age;
        }
    
  6. ここで説明したようなことは new で生成して、ポインタで渡す限り知る必要はありません。
    Class は new で生成して、パラメータで渡すときはポインタを使う方法をお勧めします。

超初心者のプログラム入門(C/C++)