public 상속(is- a 관계)이 아닌 private 상속을 살펴보자.
class Person {…};
class Student : private Person { … }; //private 상속
void eat(const Person& p); // 사람이든 학생이든 먹을 수 있다.
void study(const Student& s); // 공부는 학생만할 수 있다.
Person p;
Student s;
eat(p); // OK ! p는 Person의 일종이다.
eat(s); // Error! Student는 Person의 일종이 아니다.(public 상속이 아니기 때문에)
1. private 상속의 특징
1) 파생클래스 객체(Student)에서 기본클래스 객체(Person)로 변환하지 않는다.
* 기본클래스의 접근영역이 protected, public이었음에도 불구하고(즉, protected, public -> private 化 한다.)
2) private 상속의 의미는 즉, is-implemented-in-terms-of처럼 구현기법중 하나다.
* private 는 is-imple..의 포함관계라고 생각하면 되겠다.
Q. 객체합성도 private상속과 같이 is-imple..의 뜻을 가진다고 하였다. 그럼 2가지 中 어떤 걸 사용해야할까?
A. 될 수 있으면 객체 합성을 사용하고, 꼭 해야 한다면 private 상속을 쓰자.
( * private 상속은 다른 클래스의 비공개 멤버 접근이 필요하거나, 가상함수를 재정의할때 쓴다. )
2. private 상속 VS 객체합성
1) 기본 클래스 Timer
class Timer {
public :
explicit Time(int tickFrequency);
virtual void onTick() const; // 일정 시간 초과시 이함수가 호출된다.
};
자, 이제 Timer의 onTick() 을 다른클래스에서 사용해보고 싶다. ( is-imple… 구현기법)
2) private 상속으로 풀어가보자.
class Widget : private Timer{
private:
virtual void onTick() const;
…
};
* 풀이 : Timer의 가상함수를 Widget 클래스에서 재정의가 필요하므로 상속을 받았다.
Widget과 Timer는 is-a 관계가 아니므로 private 상속을 구현하였다.
또한, Widget객체의 사용자는 Widget객체를 통해 onTick함수를 호출해선 안된다.
이 함수는 개념적으로 Widget의 인터페이스로 볼 수 없기 때문이다.
항목 18. (제대로 사용하기쉽게…)을 다시 확인해보자. onTick을 public을 빼놓는순간 항목18. 위반이다.
3) 객체합성으로 풀어가보자.
class Widget{
private :
class WidgetTimer : public timer{
public :
virtual void onTick() const;
…
};
WidgetTimer timer;
…
};
* 풀이 : 상당히 복잡한 구조다. public 상속 + 객체 합성
장점1. Widget클래스를 파생 가능하게 하되, onTick()을 재정의 할 수 없도록 막아 두었다. private상속으로 구현했다면, 가상함수를 호출 할 수는 없으나, 재정의는 가능했을 것이다.
장점2. 컴파일 의존성을 최소화할 수 있다. WidgetTimer의 정의를 Wiget으로 부터 빼내고 Widget이 WigetTimer객체에 대한 포인터만 빼두면 #include 없이 사용가능하다.
3. 결론
* private 상속이 최선인 경우는 아무리 봐 주어도 is-a관계로 이어질 것 같지 않을 두 클래스를 사용해야하는데, 한쪽이 다른쪽 클래스의 protected 또는 private의 접근이 필요할때, 또는 다른쪽클래스의 가상함수를 재정의해야할때이다.
설계가 필요할 시 private 상속은 가장 마지막 우선순위로 두고, 다른방법을 먼저 생각해보자.(ex. 객체합성 + public 상속)
이것만은 잊지 말자!
- private 상속의 의미는 is-implemented-in-terms-of 이다. 객체합성에 비해 쓰이는 경우가 많지 않다. 하지만, is-a 관계가 아닌 다른클래스의 가상함수를 재정의할때, 비공개영역을 접근해야할때 private 상속을 사용한다.
- 객체 합성과 달리 private 상속은 기본클래스 최적화(EBO)를 활성화 시킬 수 있다. 이 점은 객체 크기를 가지고 고민하는 개발자에게 꽤 매력적이다. (내용 pass 하였다...2020.03.16)
'책 정리 > Effective C++ 3rd' 카테고리의 다른 글
항목 41. 템플릿 프로그래밍의 천릿길도 암시적 인터페이스와 컴파일 타임 다형성부터 (0) | 2020.03.17 |
---|---|
항목 40. 다중 상속은 심사숙고해서 사용하자 (0) | 2020.03.16 |
항목 38. "has-a(…는 …를 가짐)" 혹은 "is-implemented-in-terms-of(…는…를 써서 구현됨)"를 모형화할 때는 객체 합성을 사용하자 (0) | 2020.03.12 |
항목 37. 어떤 함수에 대해서도 상속받은 기본 매개변수 값은 절대로 정의하지 말자 (0) | 2020.03.10 |
항목 36. 상속받은 비가상 함수를 파생 클래스에서 재정의하는 것은 절대 금물! (0) | 2020.03.10 |
댓글