일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- Flutter
- 다트 언어
- 플러터
- Houdini
- c#
- C언어 포인터
- git
- dart 언어
- 도커
- jupyter lab
- github
- Algorithm
- jupyter
- 포인터
- C++
- 구조체
- c# 윈폼
- Unity
- vim
- c# 추상 클래스
- gitlab
- c언어
- 깃
- c# winform
- docker
- HTML
- 유니티
- Python
- C# delegate
- Data Structure
- Today
- Total
nomad-programmer
[Programming/C++] 가상 상속(Virtual Inheritance) 본문
함수 호출관계 모호함은 다음과 같은 상황에서도 발생할 수 있다.
#include <iostream>
#include <cstring>
#pragma warning(disable: 4996)
using std::cout;
using std::cin;
using std::endl;
class Base {
public:
explicit Base() {
cout << "Base Constructor" << endl;
}
void SimpleFunc() {
cout << "BaseOne" << endl;
}
};
class MiddleDerivedOne : virtual public Base {
public:
explicit MiddleDerivedOne() : Base() {
cout << "MiddleDerivedOne Constructor" << endl;
}
void MiddleFuncOne() {
SimpleFunc();
cout << "MiddleDerivedOne" << endl;
}
};
class MiddleDerivedTwo : virtual public Base {
public:
explicit MiddleDerivedTwo() : Base() {
cout << "MiddleDerivedTwo Constructor" << endl;
}
void MIddleFuncTwo() {
SimpleFunc();
cout << "MiddleDerivedTwo" << endl;
}
};
class LastDerived : public MiddleDerivedOne, public MiddleDerivedTwo {
public:
explicit LastDerived() : MiddleDerivedOne(), MiddleDerivedTwo() {
cout << "LastDerived Constructor" << endl;
}
void ComplexFunc() {
MiddleFuncOne();
MIddleFuncTwo();
SimpleFunc();
}
};
int main(const int argc, const char* const argv[]) {
cout << "객체생성 전..." << endl;
LastDerived ldr;
cout << "객체생성 후..." << endl;
ldr.ComplexFunc();
return 0;
}
/*
객체생성 전...
Base Constructor
MiddleDerivedOne Constructor
MiddleDerivedTwo Constructor
LastDerived Constructor
객체생성 후...
BaseOne
MiddleDerivedOne
BaseOne
MiddleDerivedTwo
BaseOne
*/
상속 구문에서 보이는 것이 '가상 상속'이다. 가상 상속은 키워드 virtual의 선언을 통해 이뤄진다.
위의 코드에서 보이는 상속의 구조는 다음과 같다. 여기서 중요한 것은 LastDerived클래스가 Base클래스를 간접적으로 두 번 상속한다는 점이다.
때문에 virtual선언이 되지 않은 상태에서 객체가 생성되면 다음 그림의 형태가 된다. (Base클래스의 멤버가 두 번 포함되었음에 주목)
이렇듯 하나의 객체 내에 두 개의 Base클래스 멤버가 존재하기 때문에 ComplexFunc함수 내에서 이름만 가지고 SimpleFunc함수를 호출할 수 없다.
따라서 이 경우에는 다음과 같이, 어느 클래스를 통해서 간접 상속한 Base클래스의 멤버함수를 호출할 것인지 명시해야 한다.
- MiddleDerivedOne::SimpleFunc();
- MiddleDerivedOne클래스가 상속한 Base클래스의 SimpleFunc함수호출을 명령
- MiddleDerivedTwo::SimpleFunc();
- MiddleDerivedTwo클래스가 상속한 Base클래스의 SimpleFunc함수호출을 명령
그런데 이러한 상황에서, Base클래스의 멤버가 LastDerived객체에 하나씩만 존재하는 것이 타당한 경우가 대부분이다.
즉, Base클래스를 딱 한번만 상속하게끔 하는 것이 더 현실적인 해결책이 될 수 있다. 그리고 이를 위한 문법이 바로 '가상 상속'이다.
class MiddleDerivedOne : virtual public Base { ... };
class MiddleDerivedTwo : virtual public Base { ... };
이렇듯, 가상으로 Base클래스를 상속하는 두 클래스를 다음과 같이 다중으로 상속하게 되면,
class LastDerived : public MiddleDerivedOne, public MiddleDerivedTwo { ... };
다음 그림에서 보이듯이, LastDerived객체 내에서 MiddleDerivedOne클래스와 MiddleDerivedTwo클래스가 동시에 상속하는 Base클래스의 멤버가 하나씩만 존재하게 된다.
그래서 위의 코드에서 SimpleFunc함수를 이름만 가지고 호출할 수 있는 것이다. 그리고 실행결과를 보면 실제로 Base클래스의 생성자가 한번만 호출되는 것을 확인할 수 있다.
만약에 가상 상속을 하지 않는다면, Base클래스의 생성자는 두 번 호출된다.
'Programming > C++' 카테고리의 다른 글
[Programming/C++] new/delete 연산자 오버로딩 (0) | 2021.02.05 |
---|---|
[Programming/C++] 2차원 배열접근에 대한 연산자 오버로딩의 예 (0) | 2021.02.05 |
[Programming/C++] 가상함수의 동작원리와 가상함수 테이블 (1) | 2021.02.03 |
[Programming/C++] 가상 소멸자(Virtual Destructor) (2) | 2021.02.02 |
[Programming/C++] 다형성(Polymorphism) <가상함수(Virtual Function), 순수 가상함수(Pure Virtual Function), 추상 클래스(Abstract Class)> (0) | 2021.02.01 |