Introduction
忘備録。
今更すぎる内容だけど、きちんと意味を理解したいので書いておく。
Examples
通常のコンストラクタの挙動
1 |
|
実行すると下記のようになる。
1 | constructor |
ポイントは
- MyClass オブジェクト m を、変数 n に代入する時にはコンストラクタは呼ばれないが、オブジェクト m の内容はコピーされる
- オブジェクトの内容が完全にコピーされるが、メンバー変数がポインタが含まれる場合は、そのアドレスがコピーされることになる
- 一方のオブジェクト内で m_num を操作すると、もう片方に影響を及ぼす
2 つ目が問題になる。
m_num も全く別のオブジェクトとしてコピーされるべきである。
つまり、オブジェクトの生成を行い、そのオブジェクトの中身も連鎖的にコピーされることが望ましい。
そのために存在するのがコピーコンストラクタ。
コピーコンストラクタの挙動
1 |
|
実行すると下記のようになる。
1 | constructor |
ポイントは
- MyClass オブジェクト m を、変数 n に代入する時にはコンストラクタは呼ばれないが、コピーコンストラクタが呼ばれるようになった
- コピーコンストラクタ内でオブジェクトを生成するように定義したため、m_num のアドレスが別、指し示す値が同じなった
ポインタの場合
当然ながら、ポインタの代入では、コピーコンストラクタは呼ばれない。
1 |
|
実行すると下記のようになる。
1 | constructor |
ポイントは
- MyClass オブジェクトのポインタ m を、変数 n に代入する時にはコピーコンストラクタも呼ばれない
- ポインタ変数 m のアドレスがポインタ変数 n にコピーされただけ
挙動としては当たり前だが、new をしないクラスオブジェクトのインスタンスの作成 (スタックへの確保) は、C# や Java ではできないので、時折混乱する時がある。
new を使ってのクラスオブジェクトのインスタンスの作成 (ヒープへの確保) は、C# や Java と同じですんなり理解できる。
間接演算子 (*) による代入の場合
この場合はコピーコンストラクタが呼び出される。
1 |
|
実行すると下記のようになる。
1 | constructor |
間接演算子によって、ポインタが指し示す先値を左辺に代入、つまりコピーが発生するため、コピーコンストラクタが呼ばれる。
間接演算子 (*) による参照代入の場合
この場合はコピーコンストラクタが呼び出されない。
1 |
|
実行すると下記のようになる。
1 | constructor |
間接演算子によって、ポインタが指し示す先値を左辺の参照変数に代入、つまりアドレスのコピーが発生することになるため、コピーコンストラクタが呼ばれない。
アドレス演算子 (&) による代入の場合
この場合はコピーコンストラクタが呼び出されない。
1 |
|
実行すると下記のようになる。
1 | constructor |
アドレス演算子によって、クラスオブジェクト m のアドレスがポインタ変数 n に代入されただけだから、コピーコンストラクタが呼ばれなかっただけ。