티스토리 뷰
목차
C++ 상속, 다이아몬드 문제란? 그리고 피하는 방법
[C++ 다중상속] Diamond problem
위 그림은 C++ 상속, 다이아몬드 문제를 이해하는 데 도움이 됩니다.
클래스 A에서 파생되는 클래스 B와 C가 있다고 가정합니다. 그리고 C++ 상속(다이아몬드를 유발하는 다중 상속)으로 클래스 B와 C의 파생 클래스 D도 생성합니다. (상상만으로도 한숨 나오는 C++ 상속 구조입니다)
여기서 C++ 상속, 다이아몬드 문제의 발생 이유가 나타납니다. 위 그림을 토대로 구체적인 코드를 작성해 보겠습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | -- Animal 클래스는 윗 그림의 클래스 D와 같습니다. -- class Animal { -- ... -- }; // base class { int weight; public: int getWeight() { return weight;}; }; class Tiger : public Animal { -- ... -- }; class Lion : public Animal { -- ... -- } class Liger : public Tiger, public Lion { -- ... -- }; | cs |
위의 코드가 C++ 상속, 다이아몬드 문제를 유발하는 실제 예시입니다.
Animal 클래스는 최상위 클래스 A와 같으며, Tiger와 Lion은 클래스 B와 C, Liger 클래스는 D 클래스에 해당합니다.
위와 같은 다중 상속으로 생기는 문제점이 무엇인지는 아래 코드에서 나타납니다.
1 2 3 4 5 6 | int main( ) { Liger lg ; --COMPILE ERROR-- int weight = lg.getWeight(); } | cs |
C++ 상속되는 계층 구조에서 Tiger와 Lion 클래스 모두 Animal이란 기본 클래스에서 파생되는 것이 확인되죠.
[C++ 다중상속] Diamond problem
C++ 상속, 다이아몬드 문제가 여기에 있습니다.
Liger 클래스에서 Tiger, Lion 클래스가 파생됨.
두 클래스 모두 Animal 클래스의 멤버 데이터와 함수를 갖게 됩니다.
Liger 객체 "lg"는 Animal을 상속받는 두 개의 클래스 모두가 보유하게 됩니다.
Liger의 객체를 보유한 2개의 서브 클래스가 "lg.getWeight()"로 호출했을 때 어떤 컴파일 에러가 발생할까요?
컴파일러는 getWeight를 호출하는 Liger 클래스의 객체 lg의 정확한 C++ 상속 관계를 알 수 없습니다.
그래서 위의 코드에선 getWeight에 대한 호출이 "모호(ambiguous)"해서 컴파일러는 정상적으로 수행되지 못합니다.
다이아몬드 문제(Diamond Problem) 해결책
위에서 C++ 상속, 다이아몬드 문제 원인을 살펴봤습니다.
이 문제를 해결할 방법은 Virtual 키워드 사용입니다. 상속 관계에서 Virtual 키워드를 사용한다면, Liger의 객체가 서브 클래스 모두에 생성되는 것을 방지할 수 있습니다.
아래는 그 예입니다.
1 2 | class Tiger : virtual public Animal { -- ... -- }; class Lion : virtual public Animal { -- ... -- }; | cs |
간단하게, Tiger와 Lion 클래스 선언 시 "Virtual" 키워드를 추가해줍니다.
1 2 3 4 5 | int main( ) { Liger lg; int weight = lg.getWeight(); } | cs |
이렇게 C++ 상속, 다이아몬드 문제를 살펴봤습니다.
[C++ 다중상속] Diamond problem
다이아몬드 상속 문제에 대해선 이거 하나만 딱 기억하세요.
쓰면 안 된다. 쓰지 마.
가끔 쓸 때는 써야 한다는 이야기도 있는데, 제 생각엔 쓸 때가 없습니다. 쓰지 않고도 구현할 방법은 있으니깐요.
C++ 상속, 다이아몬드 문제란? 그리고 피하는 방법