개발자 면접 공부/C-C++

가상상속

chogyujin 2022. 9. 17. 14:08
728x90

오늘은 가상상속에 대해서 공부하도록 하겠습니다.


가상 상속이란???

C++에는 다중 상속을 지원하지만 JAVA는 다중 상속을 지원하지 않습니다.

다중상속에는 장점도 있지만 매우 큰 단점이 하나 있습니다.

장점은 객체에 재사용성을 즉 상속성을 좀더 유연하게 만들어 줄수 있습니다.

하지만 단점으로는 다이아몬드 상속 구조를 사용할 경우 매우 큰 성능 저하 및 메모리의 낭비가 올수 있습니다.

 

아래의 그림을 보시면 다이아 몬드 상속을 대표적으로 보여주고 있습니다.

출처 : https://hwan-shell.tistory.com/224

이러한 상속 구조가 될경우 B나 C는 A를 포함하여 메모리상에 올리며 매우 좋은 상속 구조를 가질수 있지만

D같은 경우는 B 랑 C를 상속을 받지만 결국 B 랑 C는 A를 상속 받고 있기 떄문에 D는 메모리 구조상 A를 두번 할당을 받습니다.

또한, 생성자 및 소멸자를 호출할때는 꼭 부모를 타고 조상 클래스까지 호출을 합니다.

D는 B 와 C를 상속을 받고 있으므로 A의 생성자를 두번 소멸자를 두번 호출하게 됩니다.

이러면 성능적으로 매우 우아하지 못합니다.

 

코드

#include <iostream>

using namespace std;

class A {
public:
    A() { printf("A 생성자\n"); }
    ~A() { printf("A 소멸자\n"); }
    int A_num;
};

class B : public A {
public:
    B() { printf("B 생성자\n"); }
    ~B() { printf("B 소멸자\n"); }
private:
    int B_num;
};

class C : public A {
public:
    C() { printf("C 생성자\n"); }
    ~C() { printf("C 소멸자\n"); }
private:
    int C_num;
};

class D : public B, public C{
public:
    D() { printf("D 생성자\n");
    B::A_num = 0;
    }
    ~D() { printf("D 소멸자\n");
    }
private:
    int D_num;
};

int main(void) {

    D d;
    
    return 0;
}

출처 :&nbsp;https://hwan-shell.tistory.com/224

현재 D의 메모리 구조입니다. A를 두개를 받고 있습니다.

또한, A의 변수를 두번 메모리에 올리는 참사가 발생하고 말았습니다.

이를 해결할수 있는 최고의 방법은 Virtual을 사용하여 상속을 하는 방법이 있습니다.

출처 :&nbsp;https://hwan-shell.tistory.com/224

코드

#include <iostream>

class A {
public:
    A() { printf("A 생성자\n"); }
    ~A() { printf("A 소멸자\n"); }
    int A_num;
};

class B : virtual public A {
public:
    B() { printf("B 생성자\n"); }
    ~B() { printf("B 소멸자\n"); }
private:
    int B_num;
};

class C : virtual public A {
public:
    C() { printf("C 생성자\n"); }
    ~C() { printf("C 소멸자\n"); }
private:
    int C_num;
};

class D : public B, public C{
public:
    D() { printf("D 생성자\n");
    B::A_num = 0;
    }
    ~D() { printf("D 소멸자\n");
    }
private:
    int D_num;
};

int main(void) {

    D d;

    return 0;
}

불필요한 소멸자와 생성자는 사라지는것이 보일겁니다.

 

하지만 저렇게 사용하면 메모리 상 공간이 증가된결과를 얻을수 있을겁니다.

이유는 가상 테이블이 생겨서 입니다.

출처 :&nbsp;https://hwan-shell.tistory.com/224

보시면 vbptr(virtual base table pointer)이라는 것이 생겨서 입니다.

그리고 vbptr은 int A_num의 위치를 어디있는지 알려주는 역활을 합니다(offset 을 가르킴).

또한 int A_num의 위치가 메모리상 아래로 위치하게 되었습니다.

 

맨 아래로 간 이유는 중복을 막기위함이 제일 큽니다.

또한, 위치를 맨 아래를 보낸것은 offset정보를 계선할수 있기 때문입니다.

 

B의 vbptr의 오프셋을 보면 0, 20 입니다. 이걸 뭘 의미하냐면 자기 자신에서 20바이트 떨어진 곳에 A_num 변수가 있다라는 것을 알려주는 항목입니다.

 

시작 offset의 값은 D가 메모리의 적재되는 순간 해당 메모리의 기준으로 계산됩니다.

offset의 값은 -(음수)의 값이 될수도 있고 0 이 될수도 있습니다.

 

복잡하게 offset을 나눈 이유는 몇개의 상속이 올지도 모르기 때문입니다.

예측을 할수가 없기 떄문에 계산을 통해 위치를 알아내기 위해 만들어 놓은 것 입니다.

 

이렇게 되면 앞에 설명한 대로 최대의 단점인 메모리의 공간이 커지며, offset을 통해 자료를 찾는 과정에서 매우 큰 성능 저하를 유발할수 있습니다.

 


Reference

https://hwan-shell.tistory.com/224

 

C++ 가상 상속(virtual inheritance)

1. 가상 상속(virtual inheritance) 이란?? C++에선 다중상속을 지원합니다. JAVA는 다중상속을 막고 있지요. 다중상속은 장점과 단점이 존재합니다. 장점으론 객체지향의 상속성을 좀 더 유연하게 해주

hwan-shell.tistory.com

 

'개발자 면접 공부 > C-C++' 카테고리의 다른 글

C++ STL 장단점  (0) 2022.09.21
C++의 인터페이스(Interface)  (0) 2022.09.17
C++ 객체지향 언어 4가지 특징  (0) 2022.09.01
A* 알고리즘  (0) 2022.08.24
다익스트라 vs BFS  (0) 2022.08.11