[ create a new paste ] login | about

Link: http://codepad.org/BA4Kwh5P    [ raw code | output | fork ]

C++, pasted on Feb 8:
// 
// C++ の深遠に少し近づけるかもしれないコピコン(コピー・コンストラクタ)と
// 演算子オーバロードの罠(?)の話
// 

void hr() { printf("-----------------------------\n"); }
void sub1();
void sub2();

// ---------------------------------------------------------------------
// とりあえず、こんなクラスがあるとする
class Foo {
public:
	int val;

	Foo(): val(0) {}
	Foo(int i): val(i) {}
};

int main()
{
	// その1 ----------------------------
	{
		Foo a, b;	// 二つ用意して ※暗黙のデフォルトコンストラクタで生成
		a = b;		// コピーしちゃう
		
		// 当たり前だがどちらも同じ。どっちも 0 だからわかんね
		printf("1. a = %d, b = %d\n", a.val, b.val);
		hr();
	}

	// その2 ----------------------------
	{	
		Foo a(123), b(456);	// 明示的にコンストラクタ呼んで生成
		a = b;
	
		// やっぱ同じ
		printf("2. a = %d, b = %d\n", a.val, b.val);
		hr();
	}
	
	sub1(); sub2();
	
	printf("おわり\n");
	
	return 0;
}

// ---------------------------------------------------------------------
// 続いて、こんなクラスがあるとする。基本は Foo と似せてるが‥‥
class Bar {
public:
	int val;

	Bar(): val(0) {}
	Bar(int i): val(i) {}
	
	Bar(const Bar &bar)				// コピーコンストラクタ
	{
		val = bar.val + 1000;		// こっちでコピーされた時は 1000をプラス
	}
	
	Bar& operator=(const Bar &bar)	// =演算子オーバロード
	{
		val = bar.val + 5000;		// こっちでコピーされた時は 5000をプラス
		return *this;
	}
};

void sub1()
{
	// その3 ----------------------------
	{	
		Bar a(123), b(456);
		a = b;
	
		// 走ったのは、見た目通り = 演算子の方
		printf("3. [[ a = %d ]]  b = %d\n", a.val, b.val);
		hr();
	}

	// その4 ----------------------------
	{	
		Bar b(456);
		Bar a(b);			// コピーコンストラクタ
	
		// やはり走ったのは、見た目通りコピコンの方
		printf("4. [[ a = %d ]] b = %d\n", a.val, b.val);
		hr();
	}

	// その5 ----------------------------
	{	
		Bar b(456);
		Bar a = b;			// じゃあこれは‥‥
	
		// どっち?
		printf("5. [[ a = %d ]] b = %d\n", a.val, b.val);
		hr();
	}
}

// ---------------------------------------------------------------------
//
// 上の "その5" で実行されたのは見かけに反してコピーコンストラクタ。
// これは「暗黙のコピー生成」と解釈されたケース。なんでそんな事するのかと言うと、
//
// 例えば Bar a = b; とある時、この実際の動きは本来の流れで言うと
// 
//  1. Bar a を生成
//  2. a に b をコピー
// 
// になるんだが、この時 1 の a は「生まれた瞬間にコピーで消される」訳で、
// それだと無駄じゃね意味なくね、って話。なら最初っから『むしろ見た目通り』、
// a は b のコピーによって生まれようとしてる、んだから、コピーコンストラクタ呼んじまえよおい
// と言う事。 = 暗黙のコピーコンストラクタが呼ばれる理由でした
//

// そんな訳で、次に Bar を若干変更したクラス
class Baz {
public:
	int val;

	Baz(int i): val(i) {}
	
	explicit Baz(const Baz &baz)	// ※明示的なコピーコンストラクタ※
	{
		val = baz.val + 20000;		// これでコピーされた場合 2万をプラス
	}
};

void sub2()
{
	// その6 ----------------------------
	{	
		Baz b(456);
		Baz a(b);			// ※明示的に、コピーコンストラクタを使う※
	
		printf("6. [[ a = %d ]] b = %d\n", a.val, b.val);
		hr();
	}

	// その7 ----------------------------
	{	
		//Baz b(456);
		//Baz a = b;			// 暗黙コピー?‥‥
	
		// しかし、コピーコンストラクタは「呼ばれない」※コメント外すと上でエラー出るはず
		//printf("7. [[ a = %d ]] b = %d\n", a.val, b.val);
		//hr();
	}
	
	// 何故なら、上で "explicit = 明示的な" と宣言したから
}


Output:
1
2
3
4
5
6
7
8
9
10
11
12
13
1. a = 0, b = 0
-----------------------------
2. a = 456, b = 456
-----------------------------
3. [[ a = 5456 ]]  b = 456
-----------------------------
4. [[ a = 1456 ]] b = 456
-----------------------------
5. [[ a = 1456 ]] b = 456
-----------------------------
6. [[ a = 20456 ]] b = 456
-----------------------------
おわり


Create a new paste based on this one


Comments: