2011-11-16 4 views
5

내가 상속에 대해 읽고 있어요 그리고 내가 시간 동안 해결할 수 없었던 중요한 문제가 있습니다가상 상속 혼란

클래스 Barvirtual 기능을 가진 클래스가 주어

,

class Bar 
{ 
    virtual void Cook(); 
}; 

class Foo : public Bar 
{ 
    virtual void Cook(); 
}; 

01 : 사이의 차이가 무엇

? 인터넷 검색 및 독서의 시간은 용도에 대한 많은 정보가 있었지만 실제로는 둘 사이의 차이점을 알려주지 않으며 더 이상 혼란 스럽습니다.

+2

주제가 너무 얕아서는 안되기 때문에 대답하지 않을 것입니다.하지만 '가상'이 없으면 '막대'를 상속 한 각 클래스는 '가상'이있는 '막대'의 사본을 갖게됩니다. 가장 많이 파생 된 클래스에는 'Bar'복사본이 하나만 있습니다. –

+0

시도 : [이 검색] (http://stackoverflow.com/search?q = 가상 + 상속 + % 5Bc % 2B % 2B % 5D) –

+0

가능한 복제본 [In C++ 가상 기본 클래스?] (http://stackoverflow.com/questions/21558/in-c-virtual-base-class) –

답변

4

가상 상속은 클래스가 Foo에서 상속되는 경우에만 관련이 있습니다.나는 다음을 정의하는 경우 :

class B {}; 
class L : virtual public B {}; 
class R : virtual public B {}; 
class D : public L, public R {}; 

그런 다음 최종 객체는 모두 LR 공유 B의 사본을 포함합니다. virtual이 없으면 D 유형의 객체는 두 개의 복사본 B을 포함하고 하나는 L, 하나는 R입니다.

모든 상속이 가상이어야한다는 인수가 있습니다 (차이가있는 경우 이 있으므로 대부분의 시간은 입니다). 그러나 실제로 가상 상속은 비싸며 대부분의 경우 일 필요는 없습니다. 잘 설계된 시스템에서는 대부분 계승이 단순히 하나 이상의 계승 된 구체적인 클래스가 될 것입니다. 그러한 구체적인 클래스는 일반적으로 에서 파생되지 않으므로 아무런 문제가 없습니다. 하지만 중요한 것은 예외입니다. 예를 들어 인터페이스를 정의한 다음 인터페이스를 확장하면 구체 구현으로 에 여러 확장을 구현할 수 있기 때문에 확장은 기본 인터페이스에서 실질적으로 을 상속해야합니다. 또는 믹스 인을 디자인하는 경우 일부 클래스는 인터페이스의 일부만 구현하고 나머지는 클래스는 이러한 클래스 중 일부 ( 인터페이스의 일부분)를 상속합니다. 상속이 공개되지 않은 경우

  • , 그것은 아마도 가상 안 (나는 본 적이 : 결국, 여부에로 criteron 사실상 여부가 너무 어려운 일이 아니다 상속하는 예외), 클래스는 기본 클래스로 설계되어 있지 않은 경우, 그렇지 않으면

  • , 그렇지 않으면

  • 상속 가상 있어야 가상 상속에 대한 필요가 없습니다.

이 몇 가지 예외가 있지만, 위의 규칙은 안전의 측면에 잘못; 가상 상속이 필요하지 않은 경우에도 사실상 상속하는 것이 "정확합니다".

마지막 요점 : 가상 기본은 항상 하지 직접 상속 (그리고 상속 가상 함을 선언합니다) 클래스, 가장 파생 클래스에 의해 초기화해야합니다. 그러나 실제로 이것은 문제가 아닙니다. 가상 상속이 적합한 경우를 보면 항상 데이터를 포함하지 않는 인터페이스에서 상속하는 경우이므로 기본 생성자 만 있습니다. 이 실질적으로 생성자가있는 클래스에서 상속 받았다고 생각하면 인수를 사용하므로 디자인에 대해 심각한 질문을 할 때입니다.

5

기능상의 차이점은 두 버전간에 큰 차이가 없음을 의미합니다. virtual 상속의 경우, 모든 구현은 일반적으로 (vptr) 포인터를 추가합니다 (virtual 함수의 경우와 동일). 어느 다중 상속을합니다 (diamond inheritance 문제) 때문에 발생하는 여러 기본 클래스 사본 또한

, virtual 상속 대표의 기본 클래스의 생성자를 호출 할 수있는 권한을 방지하는 데 도움이됩니다. 예를 들어,

class Bar; 
class Foo : public virtual Bar 
class Other : public Foo // <--- one more level child class 

그래서, 지금 Bar::Bar()Other::Other()에서 직접 호출되며 다른 기본 클래스 중 첫 번째 장소에 배치됩니다.

기능은 C++ 03에서 final class (자바) 기능을 구현하는 데 도움이 대표 :이 경우

class Final { 
    Final() {} 
    friend class LastClass; 
}; 

class LastClass : virtual Final { // <--- 'LastClass' is not derivable 
... 
}; 

class Child : public LastClass { // <--- not possible to have object of 'Child' 
}; 
3

, 차이가 없습니다. 가상 상속은 파생 클래스

struct A 
{ 
    int a; 
}; 

struct B : public virtual A 
{ 
    int b; 
} 

struct C : public virtual A 
{ 
    int c; 
}; 

struct D : public B, public C 
{ 
}; 

D의 인스턴스의 멤버 변수 a의 단일 사본 거기에 의해 공유 슈퍼 클래스 하위 객체 인스턴스 관련이있다; A이 가상 기본 클래스가 아니면 의 인스턴스에 두 개의 A 하위 개체가 있습니다.

+0

"static_cast"를 사용할 때까지 "_이 경우에는 차이가 없습니다." – curiousguy

0

가상 함수는 파생 클래스에서 다른 구현을 가질 가능성이있는 함수입니다 (필수는 아니지만).

마지막 예는 가상 상속입니다. 기본 클래스에서 파생 된 두 개의 클래스 (A와 B)가 있다고 가정 해 봅시다 ('Base'라고 부름). 이제 A와 B에서 파생 된 세 번째 클래스 C를 상상해보십시오. 가상 상속이 없으면 C는 'Base'사본을 두 개 포함하게됩니다. 컴파일하는 동안 모호함을 초래할 수 있습니다. 가상 상속에서 중요한 것은 A와 B로부터의 호출이 무시되기 때문에 'Base'클래스 생성자 (있는 경우)의 매개 변수가 클래스 C에 제공되어야한다는 것입니다.

+0

"컴파일 중 모호함을 유발할 수 있습니다."**이 **는 모호함으로 이어질 것입니다. 'C'IS-A '베이스'를 사용해보십시오. – curiousguy