Minwoo Dev.

[C++] 다중 상속(Multiple Inheritance), 가상 상속(Virtaul Inheritance) 본문

C++

[C++] 다중 상속(Multiple Inheritance), 가상 상속(Virtaul Inheritance)

itisminu 2024. 7. 18. 01:44
728x90
반응형
SMALL

C++에서는 다중 상속이 가능하다.

가능하다고 하더라고 발생할 수 있는 문제점이 많아 사용하는 것을 권장하지는 않지만, 다른 언어들과는 다른 C++만의 특징이기 때문에 짚고 넘어가겠다.

 

 

다중 상속(Multiple Inheritance)

Java와 같은 언어와 다르게, C++은 두 개 이상의 부모에 대한 상속을 지원한다.

#include<iostream>
using namespace std;

class A{
public:
    A(){}
};

class B{
public:
    B(){}
};

class C: public A, public B{
public:
    C():A(),B(){}
};

 

위 코드는 클래스 A, B를 클래스 C가 다중상속을 통해 상속받고 있는 코드이다.

상속을 작성할 때는 콤마(,)를 사용하여 여러 개를 작성할 수 있다.

 

 

대부분의 프로그래밍 언어에서 다중 상속을 지원하지 않는 이유는, 다중 상속을 하게되면 서로다른 부모 클래스에서 상속받는 과정에서 겹치거나 중복되는 요소가 존재할 수 있기 때문이다.

 

#include<iostream>
using namespace std;

class BaseOne{
public:
    void SimpleFunc() { cout << "BaseOne" << endl; }
};

class BaseTwo{
public:
    void SimpleFunc() { cout << "BaseTwo" << endl; }
};

class MultiDerived : public BaseOne, protected BaseTwo{
public:
    void ComplexFunc(){
        BaseOne::SimpleFunc();
        BaseTwo::SimpleFunc();
    }
};

int main(void){
    MultiDerived mdr;
    mdr.ComplexFunc();
    return 0;
}

 

위 코드를 그림으로 나타내면 아래와 같다

 

MultiDerived 클래스에서 다중 상속으로 BaseOne과 BaseTwo를 상속받고 있기 때문에, MultiDerived 클래스의 ComplexFunc()를 실행할 때, SimpleFunc를 어떤 부모클래스에서 가져온 SimpleFunc를 사용할건지 명시해야 한다.

 

그래서 범위 지정 연산자(::)를 사용하여 코드를 작성한 것이다.

 

 

 

 

 

이것보다 더 복잡한 상속 관계에서, 예를 들어 아래 그림과 같은 상황에,

 

 

 

다이아몬드 같은 형태이다.

 

위와 같은 구조에서, 만약 생성자와 소멸자를 호출한다면, Base가 두번 -> MiddleDerivedOne 그리고 MiddleDerivedTwo -> LaseDerived 순서로 생성이 되고, 소멸될때는 LastDerived -> MiddleDerivedOne 그리고 MiddleDerivedTwo -> Base 두번이 삭제될것이다.

 

Base는 하나이므로, 굳이 두 번 생성자와 소멸자가 호출되어 메모리를 낭비할 필요가 없다.

그럴 때, 가상 상속(Virtual Inheritance)를 사용하게 된다.

 

가상 상속(Virtual Inheritance)

다중 상속으로 생성한 클래스의 부모 클래스가 생성자와 소멸자를 각각 두 번 호출하는 현상을 막기 위함

  • 상속을 표시하는 부분에 virtual을 추가한다.
  • ex ) class A : virtual public B{ ... }

 

#include<iostream>
using namespace std;

class Base{
public:
    Base() { cout << "Base Constructor" << endl; }
    void SimpleFunc() { cout << "BaseOne" << endl; }
};

class MiddleDerivedOne:virtual public Base{ // 가상 상속
public:
    MiddleDerivedOne() : Base(){
        cout << "MiddleDerivedOne Constructor" << endl;
    }
    void MiddleFuncOne(){
        SimpleFunc();
        cout << "MiddleDerivedOne" << endl;
    }
};

class MiddleDerivedTwo : virtual public Base{ // 가상 상속
public:
    MiddleDerivedTwo() : Base(){
        cout << "MiddleDerivedTwo Constructor" << endl;
    }
    void MiddleFuncTwo(){
        SimpleFunc();
        cout << "MiddleDerivedTwo" << endl;
    }
};

class LastDerived : public MiddleDerivedOne, public MiddleDerivedTwo{
public:
    LastDerived() : MiddleDerivedOne(), MiddleDerivedTwo(){
        cout << "LastDerived Constructor" << endl;
    }
    void ComplexFunc(){
        MiddleFuncOne();
        MiddleFuncTwo();
        SimpleFunc();
    }
};

int main(void){
    cout << "객체 생성 전 ...." << endl;
    LastDerived ldr;
    cout << "객체 생성 후 ...." << endl;
    ldr.ComplexFunc();
    return 0;
}

 

가상 상속을 사용하여 코드를 작성하였고, 이 코드에서는 생성자만 작성되어 있으므로 Base 클래스의 생성자가 한번만 호출되는 결과를 보인다.

 

728x90
반응형
LIST