[c++] 다이아몬드 상속(diamond inheritance)

숭글·2022년 12월 16일
0

A클래스를 상속받은 B클래스와 C클래스를 다중 상속받을 경우 발생하는 문제이다.

왼쪽 그림과 같이 다이아몬드 모양으로 상속이 될 것 같지만 사실은 오른쪽 그림과 같다. D클래스에선 B클래스가 상속받은 A클래스와 C클래스가 상속받은 A클래스가 같다는 것을 알지못한다.
-> D클래스에서 A클래스로부터 상속받은 멤버에 접근할 경우 B가 상속받은 A클래스의 멤버에 접근해야하는지 C가 상속받은 A클래스의 접근해야하는지 알지 못하는 모호성이 생긴다.

Virtual Inheritance

위 같은 문제를 가상 상속을 이용해 해결할 수 있다.
D클래스가 다중 상속 받은 B, C클래스가 A클래스를 상속받을 때 virtual 키워드를 붙이면 가상 상속을 받게된다.

virtual키워드를 붙이면 해당하는 변수, 함수들이 가상 테이블에 올라가게된다.
D클래스에서 A클래스에서 선언된 멤버에 접근할 경우 가상 테이블을 이용해 멤버에 접근하게되면서 모호성을 제거할 수 있다.

중복 호출 될 수 없는 생성자 함수

상속받은 클래스에서 생성자 함수를 구현할 경우 아래와 같이 작성한다.

D::D() : B() {};

D클래스의 객체를 생성하면 B클래스의 객체를 생성할 때 A클래스의 생성자를 자동 호출하므로 따로 명시해줄 필요가 없었다.

만약 아래처럼 A클래스의 생성자도 작성하는 경우엔 에러가 발생한다.

D::D() : A(), B() {};

하지만 D가 가상 상속을 받았다면 위같은 생성자도 문제가 없게된다. B클래스를 생성할 때 A클래스의 생성자를 호출되는 것이 아니라 D클래스를 생성할 때 A클래스의 생성자가 바로 호출될 수 있는 것이다.
가상 상속을 받을 경우 생성자 함수는 중복으로 호출할 수 없게된다.

D클래스에서 호출하는 A클래스의 생성자와 B클래스에서 호출하는 A클래스의 생성자가 같다면(인자 값까지 같다면) 크게 문제되지않지만 다른 생성자를 호출한다면 원하던 결과가 나오지 않을 수도 있다.

Class A {
	public : 
    	A() : _a(1) {};
    	A(int a) : _a(a) {};
    	~A(){};
        
    protected : 
    	int _a;
}

class B : virtual public A{
	public : 
    	B() : A(5) {};
        ~B(){};
}

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

가상 상속받은 자식클래스가 아니었다면 C클래스를 생성했을 때 멤버 변수 _a의 값은 5가 될 것이다.
하지만 가상 상속을 받은 C를 생성할 때 A클래스의 생성자가 호출됐고 _a는 이미 1로 초기화가 됐고, B클래스 생성자 함수에서는 이미 호출된 A클래스의 생성자는 호출되지 않으므로 _a는 5로 초기화될 수 없게된다.

작은 예지만 위 같은 문제가 생기지 않도록 주의해서 작성해야한다.

profile
Hi!😁 I'm Soongle. Welcome to my Velog!!!

0개의 댓글