C++에서 클래스 계층은 다이아몬드 문제(diamond problem)를 유발할 수 있습니다. 하나의 기본 클래스에서 두 개의 자식 클래스가 상속받고, 그 다음에 이 두 클래스에서 상속받는 또 다른 클래스가 생성될 때 발생합니다. 이 경우 자식 클래스의 객체는 두 개의 독립적인 기본 클래스 복사본을 포함하게 됩니다. 이 문제를 해결하기 위해 C++에서는 가상 상속을 구현했습니다.
일반적인 다중 상속을 사용하는 경우:
class A { public: int x; }; class B : public A {}; class C : public A {}; class D : public B, public C {};
객체 D는 A의 두 복사본을 포함하며: 하나는 B를 통해, 다른 하나는 C를 통해 접근합니다. 이는 A::x에 대한 접근의 모호성과 불필요한 메모리 낭비를 야기합니다.
가상 상속은 기본 클래스의 중복을 제거합니다. 기본 클래스 A의 한 인스턴스는 모든 자식 클래스가 공유합니다:
class A { public: int x; }; class B : public virtual A {}; class C : public virtual A {}; class D : public B, public C {};
이제 D는 A의 한 복사본만 가지며, A::x에 대한 접근의 모호성이 제거됩니다.
주요 특징:
범위 해석(scope resolution)을 통해 다이아몬드 문제를 해결할 수 없는 이유는 무엇인가요?
범위 해석은 기본 클래스 멤버에 대한 접근의 모호성만을 해결할 뿐, 기본 클래스의 불필요한 복사본을 제거하지는 않습니다. 이중 초기화 및 이중 데이터 저장 문제는 여전히 남아 있습니다.
가상 상속에서 생성자는 어떤 순서로 호출되나요?
가상 기본 클래스의 생성자는 가장 먼저 호출되며, 오직 한 번만 호출되며, 상속 계층에서 가장 마지막 클래스의 생성자에 의해 직접 호출됩니다.
예:
class A { public: A() { std::cout << "A "; } }; class B : public virtual A { public: B() { std::cout << "B "; } }; class C : public virtual A { public: C() { std::cout << "C "; } }; class D : public B, public C { public: D() { std::cout << "D "; } }; D d; // 출력: A B C D
클래스 선언 및 정의에서 가상 상속을 반드시 선언해야 하나요?
네, 가상 상속은 해당 기본 클래스에서 상속받을 때마다 명시해야 합니다. 그렇지 않으면 컴파일 오류가 발생하며, 다중 상속이 일반적인 결과가 됩니다.
가상 상속이 적용되지 않은 복잡한 계층 구조로 인해 객체에 두 개의 설정 복사본이 포함되어 있습니다:
장점:
단점:
가장 상위 자식의 일관된 생성자와 함께 가상 상속을 사용했습니다:
장점:
단점: