C++ 복사 생성자(copy constructor)와 대입 연산자(substitution operator)
 
class의 데이터 멤버가 포인터인 경우 복사생성자, 대입연산자를 구현하여
deep copy 해주거나 사용하지 않을 경우 private로 막는다.
 
복사생성자, 대입연산자를 정의/구현하지 않은 경우 포인터가 아닌 멤버변수는 잘 복사됨.
 
1. 복사 생성자, 대입 연산자
    미구현으로 문제가 될 현상
#include <iostream>
#include <string>
#include <tchar.h>

using namespace std;

class CSimple
{
public:
	static int count;
	CSimple()
	{
		count++;
		print("constructor()");
	}
	~CSimple()
	{
		count--;
		print("destroyer()");
	}
	CSimple(const CSimple &cls) //복사 생성자
	{
		print("copy constructor()");
	}
	CSimple& operator=(CSimple& cls) //대입 연산자
	{
		print("substitution operator()");
		return *this; //자기자신을 돌려주어야 함.
	}
	void print(const string &str = "")
	{
		cout << "\t";
		cout << " count : " << count;
		if (str.size() != 0)
			cout << " , " << str << endl;
	}
};
int CSimple::count = 0;

CSimple func_bad(CSimple cls) {
	return cls;
}

int main() {
	cout << "CSimple cls1;" << endl;
	CSimple cls1; //cls1.id = 1, constructor()
	cout << endl;

	cout << "CSimple cls2 = cls1;" << endl;
	CSimple cls2 = cls1; //cls2.id = 2, copy constructor()
	cout << endl;

	cout << "CSimple cls3;" << endl;
	CSimple cls3; //cls3.id = 2, constructor()
	cout << endl;

	cout << "cls3 = cls1;" << endl;
	cls3 = cls1; //cls3.id = 1, cls1.id = 1, substitution operator()
	cout << endl;

	cout << "CSimple cls4 = func_bad(cls1);" << endl;
	CSimple cls4 = func_bad(cls1);
	cout << endl;

	//cout << "CSimple cls5 = func_good(cls1);" << endl;
	//CSimple cls5 = func_good(cls1);
	//cout << endl;

	cout << "CSimple* clsP = &cls1;" << endl;
	cout << "cls1 = *clsP;" << endl;
	CSimple* clsP = &cls1;
	cls1 = *clsP; //가지자신을 대입
	cout << endl;

	cout << endl << endl << endl;
	cout << "End Main()" << endl;
	return 0;
}

<실행결과>

CSimple cls1;
         count : 1 , constructor()

CSimple cls2 = cls1;
         count : 1 , copy constructor()

CSimple cls3;
         count : 2 , constructor()

cls3 = cls1;
         count : 2 , substitution operator()

CSimple cls4 = func_bad(cls1);
         count : 2 , copy constructor()
         count : 2 , copy constructor()
         count : 1 , destroyer()

CSimple* clsP = &cls1;
cls1 = *clsP;
         count : 1 , substitution operator()




End Main()
         count : 0 , destroyer()
         count : -1 , destroyer()
         count : -2 , destroyer()
         count : -3 , destroyer()
계속하려면 아무 키나 누르십시오 . . .
 :(

 

 

2. 복사 생성자, 대입 연산자 구현
#include <iostream>
#include <string>
#include <tchar.h>

using namespace std;

class CSimple
{
public:
	int id;
	static int count;
	CSimple()
	{
		count++;
		id = count;
		print("constructor()");
	}
	~CSimple()
	{
		count--;
		print("destroyer()");
	}
	CSimple(const CSimple &cls) //복사 생성자
	{
		/*
		cls를 this로 depp copy 필요.
		this에 메모리 할당된게 있다면 해재 한후 cls의 내용데로 new하여 내용 복사하도록 한다.
		*/
		count++;
		id = count;
		print("copy constructor()");
	}
	CSimple& operator=(CSimple& cls) //대입 연산자
	{
		if (this == &cls) //자기자신이면 복사하지 말기
		{
			cout << "\tsubstitution operator(), Don't copy onself" << endl;
			return *this;
		}

		/*
		cls를 this로 depp copy 필요.
		this에 메모리 할당된게 있다면 해재 한후 cls의 내용데로 new하여 내용 복사하도록 한다.
		*/
		count++;
		id = count;
		print("substitution operator()");
		return *this; //자기자신을 돌려주어야 함.
	}
	void print(const string &str = "")
	{
		cout << "\t";
		cout << "class id : " << id;
		cout << ", count : " << count;
		if (str.size() != 0)
			cout << " , " << str << endl;
	}
};
int CSimple::count = 0;

// Pass and return BY VALUE:
CSimple func_bad(CSimple cls) {
	//인자로 받는 cls에서 copy constructor() 호출됨. (불필요한 작업 발생)
	//리턴되는 cls에서 copy constructor() 호출됨.
	//인자로 받은 cls에서 destroyer() 호출됨. (불필요한 작업 발생)
	return cls;
}

CSimple func_good(CSimple &cls) { //레퍼런스 사용
 //리턴되는 cls에서 copy constructor() 호출됨.
	return cls;
}

int main() {

	cout << "CSimple cls1;" << endl;
	CSimple cls1; //cls1.id = 1, constructor()
	cout << endl;

	cout << "CSimple cls2 = cls1;" << endl;
	CSimple cls2 = cls1; //cls2.id = 2, copy constructor()
	cout << endl;

	cout << "CSimple cls3;" << endl;
	CSimple cls3; //cls3.id = 2, constructor()
	cout << endl;

	cout << "cls3 = cls1;" << endl;
	cls3 = cls1; //cls3.id = 1, cls1.id = 1, substitution operator()
	cout << endl;

	//cout << "CSimple cls4 = func_bad(cls1);" << endl;
	//CSimple cls4 = func_bad(cls1);
	//cout << endl;

	cout << "CSimple cls5 = func_good(cls1);" << endl;
	CSimple cls5 = func_good(cls1);
	cout << endl;

	cout << "CSimple* clsP = &cls1;" << endl;
	cout << "cls1 = *clsP;" << endl;
	CSimple* clsP = &cls1;
	cls1 = *clsP; //가지자신을 대입
	cout << endl;


	cout << endl << endl << endl;
	cout << "End Main()" << endl;
	return 0;
}
 

<실행 결과>

CSimple cls1;
        class id : 1, count : 1 , constructor()

CSimple cls2 = cls1;
        class id : 2, count : 2 , copy constructor()

CSimple cls3;
        class id : 3, count : 3 , constructor()

cls3 = cls1;
        class id : 4, count : 4 , substitution operator()

CSimple cls5 = func_good(cls1);
        class id : 5, count : 5 , copy constructor()

CSimple* clsP = &cls1;
cls1 = *clsP;
        substitution operator(), Don't copy onself




End Main()
        class id : 5, count : 4 , destroyer()
        class id : 4, count : 3 , destroyer()
        class id : 2, count : 2 , destroyer()
        class id : 1, count : 1 , destroyer()
계속하려면 아무 키나 누르십시오 . . . 
:D

안쓸꺼면 복사 생성자, 대입 연산자를 private로 막어버리는게 좋음.

 
 
 
 
 
3. 상속받은 child class 인경우 parent class의 
   복사 생성자, 대입 연산자를 명시적으로 호출해 준다.
#include <iostream>
#include <string>
#include <tchar.h>

using namespace std;

class CParent
{
public:
	CParent() {};
	~CParent() {};
	CParent(const CParent&cls)
	{
		//deep copy
		cout << "\tparent copy constructor()" << endl;
	}
	CParent& operator=(CParent& cls)
	{
		//deep copy
		cout << "\tparent substitution operator()" << endl;
		return *this;
	}
};

class CSimple : public CParent
{
public:
	int id;
	static int count;
	CSimple()
	{
		count++;
		id = count;
		print("constructor()");
	}
	~CSimple()
	{
		count--;
		print("destroyer()");
	}
	CSimple(const CSimple &cls) : CParent(cls)  //부모 복사 생성자 호출
	{
		/*
		cls를 this로 depp copy 필요.
		this에 메모리 할당된게 있다면 해재 한후 cls의 내용데로 new하여 내용 복사하도록 한다.
		*/
		count++;
		id = count;
		print("copy constructor()");
	}
	CSimple& operator=(CSimple& cls) //대입 연산자
	{
		if (this == &cls) //자기자신이면 복사하지 말기
		{
			cout << "\tsubstitution operator(), Don't copy onself" << endl;
			return *this;
		}

		CParent::operator = (cls);   //부모 대입 연산자 호출

		/*
		cls를 this로 depp copy 필요.
		this에 메모리 할당된게 있다면 해재 한후 cls의 내용데로 new하여 내용 복사하도록 한다.
		*/
		count++;
		id = count;
		print("substitution operator()");
		return *this; //자기자신을 돌려주어야 함.
	}

	void print(const string &str = "")
	{
		cout << "\t";
		cout << "class id : " << id;
		cout << ", count : " << count;
		if (str.size() != 0)
			cout << " , " << str << endl;
	}
};
int CSimple::count = 0;

// Pass and return BY VALUE:
CSimple func_bad(CSimple cls) {
	//인자로 받는 cls에서 copy constructor() 호출됨. (불필요한 작업 발생)
	//리턴되는 cls에서 copy constructor() 호출됨.
	//인자로 받은 cls에서 destroyer() 호출됨. (불필요한 작업 발생)
	return cls;
}

CSimple func_good(CSimple &cls) {
	//리턴되는 cls에서 copy constructor() 호출됨.
	return cls;
}

int main() {

	cout << "CSimple cls1;" << endl;
	CSimple cls1; //cls1.id = 1, constructor()
	cout << endl;


	cout << "CSimple cls2 = cls1;" << endl;
	CSimple cls2 = cls1; //cls2.id = 2, copy constructor()
	cout << endl;

	cout << "CSimple cls3;" << endl;
	CSimple cls3; //cls3.id = 2, constructor()
	cout << endl;

	cout << "cls3 = cls1;" << endl;
	cls3 = cls1; //cls3.id = 1, cls1.id = 1, substitution operator()
	cout << endl;

	//cout << "CSimple cls4 = func_bad(cls1);" << endl;
	//CSimple cls4 = func_bad(cls1);
	//cout << endl;

	cout << "CSimple cls5 = func_good(cls1);" << endl;
	CSimple cls5 = func_good(cls1);
	cout << endl;

	cout << "CSimple* clsP = &cls1;" << endl;
	cout << "cls1 = *clsP;" << endl;
	CSimple* clsP = &cls1;
	cls1 = *clsP; //가지자신을 대입
	cout << endl;


	cout << endl << endl << endl;
	cout << "End Main()" << endl;
	return 0;
}
 
<실행 결과>
CSimple cls1;
        class id : 1, count : 1 , constructor()

CSimple cls2 = cls1;
        parent copy constructor()
        class id : 2, count : 2 , copy constructor()

CSimple cls3;
        class id : 3, count : 3 , constructor()

cls3 = cls1;
        parent substitution operator()
        class id : 4, count : 4 , substitution operator()

CSimple cls5 = func_good(cls1);
        parent copy constructor()
        class id : 5, count : 5 , copy constructor()

CSimple* clsP = &cls1;
cls1 = *clsP;
        substitution operator(), Don't copy onself




End Main()
        class id : 5, count : 4 , destroyer()
        class id : 4, count : 3 , destroyer()
        class id : 2, count : 2 , destroyer()
        class id : 1, count : 1 , destroyer()
계속하려면 아무 키나 누르십시오 . . . 
: )


 
 

'C++' 카테고리의 다른 글

ActiveX control  (0) 2010.11.04
OLE (Object Linking and Embedding)  (0) 2010.11.04
Automation (자동화)  (0) 2010.11.02
COM (component object model)  (1) 2010.11.02
STL (Standard Template Library)  (0) 2010.11.01
C++ 파일과 콘솔 출력 예제  (0) 2010.11.01
Registry 레지스트리  (0) 2010.10.27
DLL (Dynamic Link Library)  (0) 2010.10.27