virtual 상속

다중 상속으로 인해 발생하는 문제를 보여주는 예제 입니다.

#include <iostream>
using namespace std;
class A
{
public:
 int n;
 A(int a)
 {
 cout << "A::A(): " << a << endl;
 n = a;
 }
};
class B1 : public A
{
public:
 B1() : A(11)
 {
 cout << "B1::B1(): " << A::n << endl;
 }
};
class C1 : public A
{
public:
 C1() : A(12)
 {
 cout << "C1::C1(): " << A::n << endl;
 }
};
class D1 : public B1, public C1
{
public:
 D1()
 {
 cout << "D1::D1()" << endl;
 cout << "B1::n: " << B1::n << endl;
 cout << "C1::n: " << C1::n << endl;
 }
};
class B2 : virtual public A
{
public:
 B2() : A(11)
 {
 cout << "B2::B2(): " << A::n << endl;
 }
};
class C2 : virtual public A
{
public:
 C2() : A(12)
 {
 cout << "C2::C2(): " << A::n << endl;
 }
};
class D2 : public B2, public C2
{
public:
 /*
 아래는 컴파일 에러 발생
 이유는 D2를 생성할 때에 A의 기본 생성자가 없으므로 컴파일러가 오류를 발생시킨다
 D2()
 {
 cout << "D2::D2()" << endl;
 cout << "B2::n: " << B2::n << endl;
 cout << "C2::n: " << C2::n << endl;
 }
 */
 D2() : A(21)
 {
 cout << "D2::D2()" << endl;
 cout << "B2::n: " << B2::n << endl;
 cout << "C2::n: " << C2::n << endl; } }; int main(void) { D1 d1; D2 d2; char ch; cin >> ch;
 return 0;
 /*
 output:
 A::A(): 11
 B1::B1(): 11
 A::A(): 12
 C1::C1(): 12
 D1::D1()
 B1::n: 11
 C1::n: 12
 A::A(): 21
 B2::B2(): 21
 C2::C2(): 21
 D2::D2()
 B2::n: 21
 C2::n: 21
 */
}

위 예제의 출력에서 가장 중요한 것은 각 생성자에서 출력하는 내용입니다.

D1은 11과 12를 출력하고 D2는 21을 출력합니다.
D1은 B1과 C1을 통해서 A 클래스를 위한 메모리 공간을 각각 따로 만들었기 때문에 A::n의 값이 두 종류 11과 12가 되었습니다.

D2는 B2와 C2가 virtual 로 A를 상속했기 때문에 D2 생성자에서 명시적으로 A의 생성자를 호출해야 하며,
A 클래스가 메모리에 1개만 올라가 B2::n, C2::n으로 A::n을 참조할 때에 같은 값인 21이 출력됩니다.

여기서… 정말 더 중요한 것!!!

만약 코딩을 하는데 virtual 상속이 필요한 경우가 있다면… 구조를 다시 한번 되돌아보고 잘못된 것이 없는지 확실하게 확인을 해야 할 것입니다.
Java에서 다중 상속을 버린 것이 그냥 심심해서가 아니기 때문이죠.

다중 상속이 필요하다면 Java에서 인터페이스를 선언하고 구현하는 방법을 추천합니다.
이와 유사한 방법이 COM 인터페이스 정도 될까요?