페이지

2015년 1월 4일 일요일

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

* 객체 복사 함수는 주어진 객체의 모든 데이터 멤버 및 모든 부모 Class 부분을 빠뜨리지 말고 복사해야 합니다.

 객체 복사 함수 (복사 생성자 와 복사 대입 연산자)를 직접 선언한다는 것은, Compiler가 만든 기본 동작에 무너가 마음에 안드는 것이 있다는 얘기다. 이에 Compiler도 썩 반기는 분위기는 아니라, 꽤나 까칠한 자세로 골탕 먹이려 할 것이다. 어떻게 하는고 하니, 직접 구현한 복사 함수가 확실히 틀렸을 경우에도 입 다물어 버린다.

 Class에 새로운 변수를 추가하고는 복사함수에 추가하지 않는 실수를 자주 하게 된다. 이런 상황에 대해 일언반구라도 해 주는 Compiler는 거의 없다. 멋대로 만든 복사 함수에 대한 Compiler의 피맺힌 한풀이라고 보면 되겠다. Compiler가 정성스레 함수를 마련해 주겠다는데 거절했으니, 스스로 구현한 것은 죽이 되든 밥이 되든 입도 뻥끗안하겠다는 거다.

 Class 상속의 경우에도 자기 자신 Class의 멤버들만 복사하게 된다. 이 경우 부모 Class의 복사함수를 사용하면 된다.

class Base { ... };

class Derived {
public:
    Derived(const Derived& rhs)
        : Base(rhs)
        , priority (rhs.priority)
    { }

    Derived& operator=(const Derived& rhs) {
        Base::operator=(rhs);
        priority = rhs.priority;
        return *this;
    }
private:
    int priority;
};

* Class의 복사 함수 두 개를 구현할 때, 한쪽을 이용해서 다른 쪽을 구현하려는 시도는 절대로 하지 마세요. 그 대신, 공통된 동작을 제3의 함수에다 분리해 놓고 양쪽에서 이것을 호출하게 만들어서 해결합시다.

 Code 중복을 피할려는 기특한 마음이야 뭐라 할 건 아니지만, 한쪽에서 다른 쪽을 호출하는 식으로 두 개의 복사 함수를 만들면 그걸로 OK 일 것 같은가 ? KO 당한다.

 복사 대입 연산자에서 복사 생성자를 호출하는 것은 말도 안되는 발상이다. 이미 만들어져 버젓이 존재하는 객체를 또 '생성'하고 있으니깐. 태어난 아이에게 엄마 뱃속으로 들어가라는 말하는 꼴이 아닌가 ?

 반대로 복사 생성자에서 복사 대입 연산자를 호출하는것은 ? 이 역시 넌센스다. 생성자의 역할은 새로 만들어진 객체를 초기화하는 것이지만, 대입 연산자는 이미 초기화가 끝난 객체에 값을 주는 것이다.

 어쩌다 보니 복사 생성자와 복사 대입 연산자의 Code에 반복적인게 많다면, 양쪽에서 겹치는 부분을 별도의 멤버 함수에 분리해 놓은 후에 이 함수를 호출하게하는 방법은 있다. 대게 이런 함수는 private로 선언하는 경우가 많다.

댓글 없음:

댓글 쓰기