Computer >> 컴퓨터 >  >> 프로그래밍 >> C++

C++ 가상 기본 클래스(Virtual Base Class) 완벽 정리: 다이아몬드 상속 문제와 해결법

C++에서 가상 기본 클래스(virtual base class)는 파생 클래스가 기본 클래스의 복사본을 여러 개 갖게 되는 상황, 즉 흔히 말하는 '다이아몬드 상속' 문제를 해결하기 위해 사용됩니다.

문제 상황: 중복 상속으로 인한 모호성

먼저 가상 상속을 사용하지 않은 일반적인 예제를 살펴보겠습니다.

#include <iostream>
using namespace std;

class B {
public:
    int b;
};

class D1 : public B {
public:
    int d1;
};

class D2 : public B {
public:
    int d2;
};

class D3 : public D1, public D2 {
public:
    int d3;
};

int main() {
    D3 obj;

    obj.b = 40; // 오류 발생!
    obj.b = 30; // 오류 발생!
    obj.d1 = 60;
    obj.d2 = 70;
    obj.d3 = 80;

    cout << "\n B : " << obj.b;
    cout << "\n D1 : " << obj.d1;
    cout << "\n D2 : " << obj.d2;
    cout << "\n D3 : " << obj.d3;
}

왜 오류가 발생할까요?

위 예제에서 D1D2는 각각 B를 상속받으므로 둘 다 B의 복사본을 하나씩 가지고 있습니다. 그런데 D3D1D2를 동시에 상속하기 때문에 결과적으로 B의 복사본을 두 개 갖게 됩니다. 하나는 D1을 통해, 다른 하나는 D2를 통해 전달된 것입니다.

이 때문에 obj.b = 40;처럼 멤버 b에 접근하는 구문에서는 컴파일러가 어느 쪽 복사본을 참조해야 할지 판단할 수 없어 모호성(ambiguity) 오류가 발생합니다.

해결 방법: virtual 키워드로 가상 상속하기

D3에서 B의 중복 복사본을 제거하려면, D1D2B를 상속할 때 virtual 키워드를 사용해야 합니다. 이렇게 하면 컴파일러는 최종 파생 클래스에서 공통 기본 클래스의 인스턴스를 단 하나만 생성합니다.

#include<iostream>
using namespace std;

class B {
public:
    int b;
};

class D1 : virtual public B {
public:
    int d1;
};

class D2 : virtual public B {
public:
    int d2;
};

class D3 : public D1, public D2 {
public:
    int d3;
};

int main() {
    D3 obj;

    obj.b = 40; // 구문 3
    obj.b = 30; // 구문 4

    obj.d1 = 60;
    obj.d2 = 70;
    obj.d3 = 80;

    cout << "\n B : " << obj.b;
    cout << "\n D1 : " << obj.d1;
    cout << "\n D2 : " << obj.d2;
    cout << "\n D3 : " << obj.d3;
}

실행 결과

B : 30
D1 : 60
D2 : 70
D3 : 80

결과 분석

가상 상속을 적용한 후에는 D3 객체 안에 B의 복사본이 단 하나만 존재합니다. 따라서 b에 대한 접근이 더 이상 모호하지 않으며, 구문 4(obj.b = 30;)가 구문 3(obj.b = 40;)에서 설정한 값을 덮어쓰게 되어 최종적으로 30이 출력됩니다.

정리

  • 다중 상속 구조에서 같은 기본 클래스가 여러 경로로 상속되면 복사본이 중복되어 모호성 오류가 발생합니다.
  • 중간 클래스들이 기본 클래스를 virtual로 상속하면, 최종 파생 클래스에는 기본 클래스의 인스턴스가 하나만 생성됩니다.
  • 이 기법은 C++의 대표적인 상속 구조 문제인 '다이아몬드 상속(diamond inheritance)' 문제를 해결하는 표준적인 방법입니다.