객체의 모든 부분을 빠짐없이 복사하자.


이 항목의 핵심은

복사생성자, 복사 대입연산자를 (복사 함수)

내가 직접 선언할 경우에 대한 문제점이다.


이러한 복사 함수를 직접 선언할 경우

어떤 문제점이 있는지 들여다 보자.




class AAA{

private:

int a;

public:

AAA(int _a) : a(_a){};

AAA(const AAA& ra){

a = ra.a;

}

AAA& operator=(const AAA& ra){

a = ra.a;

return *this;

}

}


모든 멤버(하나밖에 없긴 하지만)를

복사하는 복사함수이다. 여기까진 문제가 없어보이지만

클래스의 멤버 변수로 int b; 라는 놈이 선언되었다면

이 복사함수 내에서 a는 복사가 되지만 b는 복사가 되지 않는다.

더 큰 문제점은 컴파일러가 어떠한 경고 메세지도 주지 않는다는 점!


클래스의 상속에서 이러한 문제는 더 뚜렷하게 드러난다.



출력 결과

1

2


파생클래스에서 복사 대입연산자를 선언하고

자신의 멤버를 빠짐없이 대입한다.

하지만 기본 클래스의 멤버의 대입은 이루어 지지 않는다.


만약 이 대입 연산자를 자신이 생성하지 않았다면

기본 클래스의 멤버까지 말끔하게 복사 대입해준다.

(복사 생성자도 위와 같은 현상을 보인다.)


위의 경우에 복사생성자는 선언해 주지 않았다.

기본 클래스의 멤버 변수까지 완벽하게 복사가 되었다.

(기본 복사 생성자에 의해)




자신이 복사생성자를 선언해주려면

BBB(const BBB& rb) : AAA(rb) , b(rb.b) {};

이런 식으로 기본생성자에 대한 복사를

빠뜨리지 않도록 각별히 주의해야 한다.


복사 대입 연산자의 경우에도

BBB& operator=(const BBB& rb){

AAA::operator(rb);

...

return *this;

}




정리

1. 해당 클래스의 데이터 멤버를 모두 복사한다.

2. 이 클래스가 상속한 기본 클래스의 복사 함수도

꼬박 꼬박 호출을 해주어야 한다.



주의 사항!!

복사생성자 복사 대입연산자 내의

코드의 중복이 심하다고 해서

복사생성자 내에서 대입연산자를 호출한다거나

대입 연산자 내에서 복사 생성자를 호출하는 짓은 하면안된다.




왜??

1. 복사 대입 연산자에서 복사생성자를 호출하는 것은

이미 만들어져 있는 객체를 다시 생성하는 행위이다.


2. 복사생성자에서 대입 연산자를 호출 하는 것 또한 넌센스

생성자의 역할은 새로 만들어진 객체를 초기화 하는것

대입 연산자의 역할은 이미 초기화가 끝난 객체에 값을 주는 것

따라서 초기화된 객체에만 적용되는 것이다.




대신 코드의 내용이 비슷하다면

겹치는 부분을 별도의 함수로 만들어 놓고

private 멤버로 두고 호출해서 사용하는 방법도 있다.




POINT!!

1. 복사 함수는 모든 데이터멤버를 포함해

기본 클래스의 부분도 빠뜨리지 말아야 한다.


2. 두개의 복사 함수 한쪽을 이용해서 다른 한쪽을

구현하려는 시도는 절대로 하지 말아야한다.





+ Recent posts