[Effective C++] #40 다중 상속
Scott Meyers의 "Effective C++"를 통해, C++ 구현에 필요한 개념들을 이해하고, 기록하기 위함입니다. 해당 항목은 6장 "상속, 그리고 객체 지향 설계", 항목 40 "다중 상속은 심사숙고해서 사용하자"에 해당하는 내용입니다.
다중 상속
MI(다중 상속)이란, 어떤 클래스가 두 개 이상의 상위 클래스로부터 상속받는 형태를 말합니다. 이번 항목에서는 다중 상속 사용 과정에서 주의할 점과 적절한 상황 등을 살펴보겠습니다.
1. 모호성 문제
class A {
public:
void checkOut();
...
};
class B {
private:
void checkOut();
...
};
class C : public A, public B {...} // A와 B를 public 상속하는 C 클래스
C pc;
pc.checkOut(); //????
위 예제 코드를 살펴보겠습니다. 클래스 C는 클래스 A와 클래스 B를 함께 public 상속합니다. 따라서, C 객체가 호출하는 함수가 클래스 A와 B에 동일한 이름으로 들어있다면, 모호성을 야기할 수 있습니다. 물론, B의 checkOut은 private 영역에 선언되어, pc.checkOut() 은 A::checkOut()를 호출하겠지만, 사용자 입장에서 혼란을 줄 수 있습니다. C++의 중복 함수에 대한 최적 일치도 검사를 통해 에러가 발생할 수 도 있습니다.
2. 마름모꼴 MI
위 그림을 살펴보면, 기본 클래스와 파생 클래스 사이의 경로가 두 개 이상이 되는 상속 계통을 보여줍니다. A에 들어있는 데이터 멤버 1개는 클래스 B와 C를 통해 최종적으로 D에서는 2개의 데이터 필드가 필요해지며, 이름이 중복되거나, 서로 달라서 문제가 발생할 수 있겠죠. 이러한 다중 상속 형태를 마름모꼴 MI라고 합니다. 우리는 이러한 데이터 멤버의 중복 생성을 방지하기 위해 "가상 기본 클래스"가 필요합니다.
가상 상속, 가상 기본 클래스
class Top {...};
class Middle1 : virtual public Top {...};
class Middle2 : virtual public Top {...};
class Bottom : public Middle1, public Middle2 {...};
1. 가상 기본 클래스를 상속하는 파생 클래스는 거리와 상관없이 가상 기본 클래스의 존재를 염두해야 한다.
2. 파생 클래스를 추가 생성할 때에도 가상 기본 클래스의 초기화를 떠맡아야 합니다.
데이터 멤버의 중복 생성을 방지하기 위해 "가상 상속"을 사용합니다. 하지만, 비용적인 측면에서 가상 상속은 비효율적입니다. 가상 상속을 사용하는 클래스의 비용은 가상 상속을 사용하지 않는 클래스보다 크기가 더 큽니다. 더불어, 가상 기본 클래스의 데이터 멤버에 접근하는 속도도 상대적으로 느리고요. 쉽게 말해, 가상 상속은 비용이 비쌉니다. 더불어, 초기화 규칙이 더욱 복잡합니다. 따라서, 비 가상 상속을 기본으로 삼고, 특정한 상황에만 가상 상속을 적용해야 합니다.
다중 상속의 적절한 상황
하나의 클래스가 두 개 이상의 기본 클래스들로부터 다중 상속받고자 할 때 적절한 상황은, 하나는 인터페이스 클래스(public 상속), 그리고 다른 하나는 구현을 돕는 클래스 (private 상속) 일 경우입니다. "is-implemented-in-terms-of" 관계를 표현하기 위해 두 가지 방법이 있었죠. 하나는 객체 합성, 다른 하나는 private 상속입니다. 대부분의 경우 객체 합성이 더 좋은 효과를 누릴 수 있지만, 파생 클래스에서 가상 함수를 꼭 재정의 해야 한다면 private 상속이 필요합니다!(private 상속의 경우, 상속받은 가상 함수를 재정의하는 것은 가능하지만, 호출하는 것은 불가능하다)
'언어 > Effective C++' 카테고리의 다른 글
[Effective C++] #41 템플릿, 암시적 인터페이스, 컴파일 다형성, 유효 표현식 (0) | 2022.02.18 |
---|---|
[Effective C++] #39 private 상속 (0) | 2022.02.16 |
[Effective C++] #38 객체 합성, private 영역, "has-a" ,"is-implemented-in-terms-of" (0) | 2022.02.09 |
[Effective C++] #37 가상 함수, 기본 매개변수 (0) | 2022.02.09 |
[Effective C++] #36 비 가상 함수의 상속, 바인딩 (0) | 2022.02.04 |