Dplex

Dplex.egloos.com

포토로그


시계

통계 위젯 (화이트)

119
91
101816


가상 상속(virtual) C/C++

C++ 은 객체지향 언어의 개념에선, 자바와 달리 다중상속을 지원합니다..

자바에서는 단일상속및, 다중 인터페이스를 지원합니다.. 하지만 C++에서는 다중상속을 지원하기 때문에,

동일한 변수를 가지거나 같은 함수를 가질경우 네임스페이스를 명시하여 변수나 함수를 사용해야 합니다..

즉 A클래스와 B클래스 모두 변수 a를 가지고 있다면

두 클래스를 상속받는 클래스 입장에서는 A.a를 사용하기 위해서는 A::a로 접근하고, 마찬가지로 B.a는 B::a를 통해 사용해야 합니다.

하지만 이때, A클래스도 어떤 클래스를 상속받고, B클래스도 A가 상속받는 클래스를 상속받는다는 가정하에, 즉 죽음의 다이아몬드형태의 상속구조를 가지고 있을때... 과연 어떤일이 발생할까요..?

A클래스와 B클래스 모두 상속해주는 클래스, 즉 부모의 부모클래스는 A클래스도 상속해주고, B클래스도 상속해주게 됩니다..

이때, 손자클래스가 보는입장에서 조상클래스의 멤버를 사용할때, A의 부모인지 B의 부모인지 모호해집니다.

물론 둘다 해당하고 멤버들이 고유하지만, 누구의 부모인지 헷갈리게 됩니다..;; 당연히 사용할수 있다고 생각되지만...
C++ 입장에서는 정확히 멤버변수들의 주소로 점프해서 호출을 해야 하지만.. A가 생성될때 부모클래스가 생성되므로 메모리가 할당되고, 마찬가지로 B가 생성될때 똑같은 부모클래스가 생성되므로 마찬가지로 메모리가 할당됩니다..

즉 같은 부모가 중복되어 메모리에 적재되게 되는겁니다.. 그래서 손자 입장에서는 어떤 주소로 가서 확인해야 되는지 헷갈리기 때문에.. C++입장에서 금지되어 있습니다..

간단한 예제를 통해 확인해보겠습니다..
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
using namespace std;                                                                                                                   
 
class A
{
public:
    A(int a)
    {
        cout <<a << endl << "난 A다 " << endl << endl;
    }
};
 
class B : public A
{
public:
    B(int b):A(3)
    {
        cout << b << endl << "난 B다" << endl << endl;
    }
};
 
class C : public A
{
public:
    C(int c):A(4)
    {
        cout << c << endl << "난 C다" << endl << endl;
    }
};
 
class D : public B, public C
{
public:
    D():B(6), C(7)
    {
        cout << "난 D다" << endl << endl ;
    }
};
 
void main()
{
    D *d = new D();
}

결과에서 보면 아시다시피. D가 생성될때, 각각 B와 C를 생성하는 과정을 거칩니다.. 당연히 부모를 먼저 만들어야 자식이 생성이 되겠죠.. B와 C가 생성될때 마찬가지로 A가 생성되야 합니다..

그럼 이 과정에서 중복된 A가 생성이 되는겁니다.. 그럼 D의 입장에서 바라본 A는 B의 부모일까요 C의 부모일까요..

당연히 D의 입장에서는 모르는겁니다.. 그래서 A의 멤버 변수및 멤버함수를 사용할수 없습니다.. 아무리 같은 내용이라 할지라도...!!

자 그럼 오늘의 주제.. virtual 키워드를 통해 상속을 받으면 어떻게 될까요?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iostream>
using namespace std;
 
class A
{
public:
    A(int a)
    {
        cout <<a << endl << "난 A다 " << endl << endl;                                                                        
    }
    void print()
    {
        cout << "b";
    }
};
 
class B : virtual public A
{
public:
    B(int b):A(3)
    {
        cout << b << endl << "난 B다" << endl << endl;
    }
};
 
class C : virtual public A
{
public:
    C(int c):A(4)
    {
        cout << c << endl << "난 C다" << endl << endl;
    }
};
 
class D : public B, public C
{
public:
    D():A(10), B(6), C(7)
    {
        cout << "난 D다" << endl << endl ;
    }
};
 
void main()
{
    D *d = new D();
}

결과를 미리 확인하자면 A클래스는 한번만 상속됩니다..

B와 C클래스가 A클래스를 상속받을때.. virtual 키워드를 통해 상속받습니다.. 그리고 생성자에서 마찬가지로 A()를 통해 생성하지만.. 결과를 보시면 아시다시피 아무런 작동을 안하는걸 알수 있습니다..

그리고 앞에서 설명드린 D에서 A클래스를 당연하다는 듯이 호출을 하는것도 알수 있습니다.!

즉 virtual 키워드는 해당 상속을 받는 클래스는 정작 부모 클래스의 함수를 호출하지 못하지만.. 손자 클래스에서 당당하게 조상클래스의 멤버변수및 멤버함수를 호출하게 되는 겁니다.. 머 이런걸 만들었냐 할수 있겠지만.. 죽음의 다이아몬드 상속관계에서 유연하게 대처할수 있게 됩니다.!




덧글

  • RF 2013/06/17 06:44 # 답글

    것보다 죽음의 다이아몬드 구조를 쓸 바엔, 차라리 Java나 C#의 인터페이스를 흉내내서, 모든 멤버가 순수가상함수인 추상클래스를 상속하게 하는편이 더 낫지 않을까용. 'ㅅ'

    저가 머리가 나빠서 virtual 키워드까지 써먹으면서 다중상속을 하고싶진 않네용...
  • Dplex 2013/06/17 20:42 #

    네 맞아요..ㅋㅋ virtual 키워드를 쓰는게 아니라 다이아몬드 상속을 안쓰는게 정답이죠 !
댓글 입력 영역