Cpp クラス コピーコンストラクタ

提供:yonewiki

C++に戻る


本来の表記は「C++(Cpp) クラス コピーコンストラクタ」です。この記事に付けられた題名はテンプレート:記事名の制約から不正確なものとなっています。

※このページではC++にのみ存在する機能として、記事タイトルがC++ クラス コピーコンストラクタになっています。

クラス コピーコンストラクタ

その名前のとおりの機能ですが、すんなり理解することはやや難しい仕組みです。コピーコンストラクタは、コピーするためのコンストラクタで引数部にクラス自身のconst参照型をうけとるものです。基本的にはクラスの宣言時の初期値を代入する処理をうまく動作させるために使われます。


CTest CTest2_obj = CTest1_obj;


クラスの変数を代入演算子をつかって以下のように表現しようとしたとすると、

<syntaxhighlight2 lang="cpp"> CTest CTest1_obj; CTest CTest2_obj = CTest1_obj; </syntaxhighlight2>

という代入は、コピーコンストラクタという仕組みがない場合には、通常期待する代入とは違った動作になってしまいます。CTest2_objの値はCTest1_objと確かに同じ値を保持することになりますが、単純にCTest1_objと同じアドレスを保持することになるだけで、CTest1_objの保持している値と連動してしまいます。動的に生成されたクラス変数ならば、CTest1_objが消えれば、CTest2_objは実体の存在しないアドレスを保持していることになり、CTest2_objの保持するアドレス値をnull_ptrにするといったような細かい調整をしない限り、CTest2_objのデストラクタと呼ばれるクラス変数消滅時に必ず動作する処理で実体を消す処理がうまくいかずプログラムは異常終了します。


なんだかややこしい表現をして、おそろしい結末になるようなことを言いましたが、コピーコンストラクタをクラスに含めれば、そのような問題を解決できるということになります。


コピーコンストラクタは以下のように定義します。

CopyConstructor001.h <syntaxhighlight2 lang="cpp" line start="1">

  1. pragma once

class CCopyConstructor001 { private:

 int xxx;

public:

 //★コピーコンストラクタ
 CCopyConstructor001(const CCopyConstructor001& CconstrefCopyConstructor001_Para1);
 CCopyConstructor001(void);
 ~CCopyConstructor001(void);

}; </syntaxhighlight2> CopyConstructor001.cpp <syntaxhighlight2 lang="cpp" line start="1">

  1. include "stdafx.h"
  2. include "CopyConstructor001.h"

//★コピーコンストラクタ CCopyConstructor001::CCopyConstructor001(const CCopyConstructor001& CconstrefCopyConstructor001_Para1) {

 xxx = CconstrefCopyConstructor001_Para1.xxx;
 //★主に、メンバ変数の初期化処理を行う動作をさせる

}

CCopyConstructor001::CCopyConstructor001(void) { }

CCopyConstructor001::~CConstructor001(void) { }

</syntaxhighlight2> CopyConstructorMain.cpp <syntaxhighlight2 lang="cpp" line start="1"> int Look(CCopyConstructor001 objArgCCopyConstructor001){

   //
   return 1;

}

int main(){

  CCopyConstructor001 objCCopyContsructor001;
  iNum = Look(objCCopyContsructor001);
  return 1;

} </syntaxhighlight2>

参照型の引数によって、メインプログラム側で引数に設定されたクラスの各メンバ変数の値を取得できるため、コピーコンストラクタの中で、各メンバ変数の値を引数によって得られたクラスのメンバ変数とメンバ変数との間で、初期化の処理をする仕組みです。コピーコンストラクタの関数内では、この参照の仕組みをつかってコピーのための処理を記述できると考えてよいと思います。


 コピーコンストラクターがあれば、値渡しになっていたLook関数があっても、同じ実体を指し示すアドレスのコピーが作られ、デストラクタが呼び出されても、main関数で生成したオブジェクトのアドレスそのものではないし、Look関数に渡された引数にぶら下がっている参照変数からのメンバ変数も参照というカタチをとることになるため、Look関数が終わっても、参照型引数としてコピーして作られた方の引数クラスと同じ形式の参照型変数のアドレスやLook関数内で使ったその他のオブジェクトが消滅するだけなので、元々のmainクラスから作られたクラスの先頭アドレスにぶら下がっている実体が残っているため、main関数が終わるときに、きちんとmain関数で生成したクラスが消滅するため、問題が発生しません。そして関数の引数としても問題がなく、より役立つクラスになります。コピーコンストラクタは大事だよ。クラスの中で動的にメモリを確保するような変数があれば、コピーコンストラクタはあった方がいいです。


他の言語を知る人にとっては、もっと単純にクラスの中身をコピーできる方法を作れば良いのに…と思う人も多いかもしれません。


実際にクラス変数のコピーに関するサンプルは、また後日に記述したいと思います。


※無計画に、自分で考えながら書いてるとときどき間違っている表現をつかってしまったり、意外と自分自身、わかっていなかった部分に気付いたりしながらこの文書を作っています。できたてほやほやの記事は間違っている部分が結構ありそうです。わかりやすいとおもって読んでくれている人がいたとしたら期待を裏切りたくは無いですが、このC++関連の記事群はまだ未熟な部分もあり、理解への遠回りになってしまっていたら申し訳ないです。


C++に戻る