3

다이아몬드 상속 관련 모호성 문제를 피하기 위해 기본 클래스에서 파생 될 때 가상 키워드 사용 요구 사항을 이해합니다.'가상'상속이 기본 동작이 아닌 이유는 무엇입니까?

하지만 내 질문은 이것이 다이아몬드 문제가있을 수도 있고 없을 수도있는 클래스를 파생시킬 때 C++의 기본 동작이 아닌 이유입니다.

다이아몬드 상속이없는 상황에서 '가상'키워드를 사용하면 '해가되는'것이 있습니까? 오버 헤드가있다

+1

다이아몬드 상속을 생성하지만 원하지 않는 곳에 '가상'키워드를 사용하는 것이 위험합니다. "DollarPaymentEndpoint"및 "YenPaymentEndpoint"인 은행 계좌를 생각해보십시오.이 계좌는 각각 "AmountReceived"멤버가있는 "PaymentEndpoint"에서 상속됩니다. –

+2

[가상 키워드가 필요한 이유는 무엇입니까?] (http://stackoverflow.com/questions/13600934/why-is-the-virtual-keyword-needed)는 '가상'이 자동이 아닌 이유에 대해 설명합니다. –

+3

@DavidSchwartz 제 실수. 기본적으로 가상 상속을 사용하면 예기치 않은 공유가 만들어지고 캡슐화가 중단됩니다. 클래스가 POD가되지 않도록합니다. –

답변

4

, 그것을 시도 내 구현에

#include <iostream> 

struct Foo { 
    int a; 
}; 

struct Bar : Foo { 
    int b; 
}; 

struct Baz : virtual Foo { 
    int b; 
}; 

int main() { 
    std::cout << sizeof(Foo) << " "; 
    std::cout << sizeof(Bar) << " "; 
    std::cout << sizeof(Baz) << "\n"; 
} 

을 내가 4 8 16를 얻을. Baz 클래스는 Foo 기본 클래스 하위 객체가 기본 클래스 하위 객체 Baz에 상대적으로 나타나는 오프셋을 모르기 때문에 가상 상속에 vptr 또는 이와 동등한 메커니즘이 필요합니다. 가장 많이 파생 된 유형도 Foo을 다른 경로로 상속하는지 여부에 따라 달라집니다.

vptr에서가 있으므로

, 하나는 또한 특정 상황에서 즉, 하나 이상의 추가 indirections가 Baz* 또는 Baz& 비아 Foo::a 액세스하기 위해 필요한 :-) 오버 헤드 인, 사용될 수있을 것으로 기대. 컴파일러는 어떤 식 으로든 가장 파생 된 유형의 참조를 아는 경우이를 피하기 위해 선택할 수 있습니다.

5

가상 상속에는 런타임 오버 헤드가 있습니다. 포인터 변환에는 런타임에만 알려진 조정이 필요하며 가상 상속이 아닌 컴파일 시간에는 조정이 필요합니다. 또한 가상 기본 클래스는 최종 상속 클래스에 의해 초기화되기 때문에 클래스를 더 복잡하게 만들 수 있습니다. 가상 기본 클래스는 직접 상속 된 클래스가 아니라 필수 클래스로 초기화됩니다.

따라서 다이아몬드 구조를 특별히 원할 때만 필요합니다. 숨겨진 오버 헤드를 피하기 위해 가상이 아닌 상속을 지정하는 것을 잊지 않아야합니다. C++은 일반적으로 필요없는 기능에 대해 비용을 지불하면 안된다는 원칙을 따릅니다.