우릭가 복사 생성자와 복사 대입연산자를 직접 선언하지 않으면 컴파일러가 자동으로 만든다는 것 기억하는가? 컴파일러가 자동으로 만들어주는 복사 생성자와 복사 대입연산자는 객체의 모든 부분을 빠짐없이 복사해준다. 하지만 우리가 자동으로 만들어 주는것이 맘에 들지 않아 직접만들면 우리가 하나하나 다 복ㄱ사를 해 주어야한다. 만약 객체 안에 데이터가 추가된다면 복사 생성자, 복사 대입연산자에서 복사해주는 코드를 추가해줘야한다.
하지만 한가지 문제점이 있다. 만약 우리가 파생 클래스를 복사한다고 했을 때 파생 클래스만 복사학다면 그것은 완전한 복사가 아닌 부분 복사나 마찬가지이다. 하지만 쉽게 기본 클래스까지 복사하는 방법이 있다. 코드를 보자
class TEST1
{
private:
int nData;
public:
TEST1(){}
TEST1(const TEST1& rhs)
: nData(rhs.nData)
{}
TEST1& operator=(const TEST1& rhs) { nData = rhs.nData; }
void Set() { nData = 7777; }
operator int() { return nData; }
};
class TEST2 : public TEST1
{
private:
int nData2;
public:
TEST2() : nData2(0) {}
TEST2(const TEST2& rhs)
:TEST1(rhs), //기본 클래스
//복사 생성자 호출
nData2(rhs.nData2)
{}
TEST2& operator=(const TEST2& rhs)
{
TEST1::operator=(rhs); //기본 클래스의=연산자
//함수 호출
nData2 = rhs.nData2;
}
operator int() { return TEST1::operator int(); }
};
int _tmain()
{
TEST2 t1;
t1.Set(); //기본클래스 값 설정
cout << "t1 : " << t1 << endl;
TEST2 t2(t1); //복사생성자
cout << "t2 : " << t2 << endl;
TEST2 t3 = t1; //복사대입연산자
cout << "t3 : " << t3 << endl;
}
만약 복사 생성자와 복사 대입 연산자가 비슷하게 초기화가 된다면 private에 따로 초기화 함수를 만들어서 사용하면된다. 절대로 생성자에서 대입연산자를 호출하거나 대입연산자에서 생성자를 호출하는건 하지말자.
이것만은 잊지 말자!
1. 객체 복사 함수는 주어진 객체의 모든 데이터 멤버 및 모든 기본 클래스 부분을 빠뜨리지 말고 복사해야한다.
2. 클래스의 복사 함수 두 개를 구현할 때, 한쪽을 이용해서 다른 쪽을 구현하려는 시도는 절대로 하지 마라, 그 대신 공통된 동작을 제3의 함수에다 분리해 놓고 양쪽에서 이것을 호출하게 만들어서 해결하자