====== コピーコンストラクタをちゃんと書かないと駄目なパターン ====== ==== cPosition.h ==== #pragma once class cPosition { private: int x, y; public: int* mem; //これを追加 //インライン関数定義 void setX(int _x) { x = _x; } void setY(int _y) { y = _y; } int getX() const { return(x); } int getY() const { return(y); } cPosition(); cPosition(int _x, int _y);     //コピーコンストラクタは宣言しない=デフォルトのコピーコンストラクタが呼ばれる //デフォルトのコピーコンストラクタの動作は、とにかく全メンバコピー void printPosition(); }; ==== cPosition.cpp ==== #include "cPosition.h" #include using std::cout; using std::endl; cPosition::cPosition() :x(0),y(0),mem(nullptr) //ポインタをnullptrで初期化 { cout << "引数なしのコンストラクタ" << endl; } cPosition::cPosition(int _x, int _y) :x(_x),y(_y), mem(nullptr) //ポインタをnullptrで初期化 { cout << "引数付きコンストラクタ" << endl; } void cPosition::printPosition() { cout << "(" << this->x << ", " << this->y << ")" < int main() { //引数付きコンストラクタが呼ばれる cPosition p1(3, 4); int var = 5; p1.mem = &var; //変数varのアドレスをmemに代入 //引数なし(デフォルトコンストラクタ) cPosition p2; //デフォルトコピーコンストラクタが呼ばれる cPosition p3 = p1; p1.printPosition(); p2.printPosition(); p3.printPosition(); } ===== コピーコンストラクタの動きを確認してみる ===== #include "cPosition.h" #include int main() { //引数付きコンストラクタが呼ばれる cPosition p1(3, 4); int var = 5; p1.mem = &var; //変数varのアドレスをmemに代入 //引数なし(デフォルトコンストラクタ) cPosition p2; //デフォルトコピーコンストラクタが呼ばれる cPosition p3 = p1; p1.printPosition(); p2.printPosition(); p3.printPosition(); } これで結果を表示すると、\\ int var = 5;\\ __のアドレスが、p1.memに代入されているため *(p1.mem) は 5 になる。__\\ (これはもうそろそろわかってほしい。。。)\\ そのうえで、デフォルトのコピーコンストラクタが動くので(メンバ全コピーなので)\\ cPosition p3 = p1;により\\ p1.memの指すアドレス(= &var)とp3.memの指すアドレスは同じものになる。\\ (p3.mem = &var; を書いたのと同じ結果になる。)\\ 動的にとったメモリがある場合は、 * そのコピー元のメモリをコピー先と共有する * コピー元のメモリ状態(配列やクラスが動的に確保されている状態)がコピー先に再現され、そこに値がコピーされる どちらが望む動作なのか考えないとだめだよ。 参考ページ:\\ https://monozukuri-c.com/langcpp-copyconstructor/ \\ http://yohshiy.blog.fc2.com/blog-entry-303.html \\