즉 Software 설계(design) 에는 아무런 의미를 갖지 않으며, 단지 구현(inplementation) 중에만 의미를 가진다.
부모 Class의 모든 것을 private로 처리되어 내부적으로는 사용이 가능하지만 외부에서는 사용이 불가능하며, 다형성의 지원도 안된다.
근데 private 상속의 의미는 is-implemented-in-terms-of 인데, 왜 객체 합성을 안쓰고 private 상속을 쓸까 ?
비공개 맴버를 접근할 때나 가상 한수를 재정의할 경우가 그 경우에 속한다.
class Timer { public: explicit Timer(int tick); virtual void onTick() const; }; class Widget : private Timer { private: virtual void onTick() const; };
Widget에서 onTick()을 재정의해서 사용해야하지만, 이것을 외부에서 호출을 하면 큰일 나는 경우 위와 같이 구현이 가능하다.
하지만 꼭 private 상속을 해야하냐 ? 객체 합성으로도 가능하다.
class Widget : private Timer { private: class WidgetTimer : public Timer { public: virtual void onTick() const; }; WidgetTimer timer; };
조금 복잡하긴 하지만 가능하다. 하지만 현실적으로 private 상속 보다는 객체 합성이 더 자주 쓰인다.
첫째, 파생은 가능하되, 파생 클래스에서 onTick()을 재정의할 수 없도록 설계 차원에서 막고 싶을 때 유용하다. Java(final) 나 C#(sealed) 에서는 재정의할 수 없도록 막는게 가능하지만, C++에서는 이와 비슷하게 구현을 할 수가 있다.
둘째, Compile 의존성을 최소화 하고 싶을 때 좋다. Timer가 선언된 헤더파일을 포함하지 않고도 구현이 가능해 진다.
그럼 정말 private 상속이 객체 합성보다 좋은게 전혀 없나 ? 딱 한 경우가 있다. 크기가 0인 Class를 만든 경우가 그러하다. 이 Class만을 사용하는 경우에는 C++의 객체의 크기가 0이 될 수가 없으므로 최소 1의 값을 가지나 상속받은 Class의 크기가 0이 해당 Class의 크기가 증가하지 않는다. 하지만 다중상속에서는 해당되지 않으며, virtual 로 선언된 함수도 하나도 없어야 한다. 이러한 공간 절약 기법을 공백 기본 클래스 최적화 (empty base optimization : EBO) 라고 부른다.
* private 상속의 의미는 is-implemented-in-terms-of(..는 ..를 써서 구현됨)입니다. 대개 객체 합성과 비교해서 쓰이는 분야가 많지는 않지만, 파생 클래스 쪽에서 기본 클래스의 protected 멤버에 접근해야 할 경우 혹은 상속받은 가상 함수를 재정의해야 할 경우에는 private 상속이 나름대로 의미가 있습니다.
* 객체 합성과 달리, private 상속은 공백 기본 클래스 최적화(EBO)를 활성화시킬 수 있습니다. 이 점은 객체 크기를 가지고 고민하는 라이브러리 개발자에게 꽤 매력적인 특징이 되기도 합니다.
댓글 없음:
댓글 쓰기