C++ 상속, 다이아몬드 문제란? 그리고 피하는 방법

C++ 상속, 다이아몬드 문제란? 그리고 피하는 방법


C++ 상속, 다이아몬드 문제란


위 그림은 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++ 상속 문제


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++ 상속 다이아몬드 문제 방법


다이아몬드 상속 문제에 대해선 이거 하나만 딱 기억하세요.


쓰면 안 된다. 쓰지 마.


가끔 쓸 때는 써야 한다는 이야기도 있는데, 제 생각엔 쓸 때가 없습니다. 쓰지 않고도 구현할 방법은 있으니깐요.

이 글을 공유하기

댓글(0)

Designed by JB FACTORY