2013-10-31 1 views
4

, 나는 다음과 같은 경고 및 오류 얻을 :GCC에서 나에게 오류가 발생하는 이유는 무엇입니까? 고유 최종 재정의 없음? 아래의 코드에서

test.cpp:15: warning: direct base 'B' inaccessible in 'D' due to ambiguity 
test.cpp:15: error: no unique final overrider for 'virtual void A::f()' in 'D' 

을하지만 A (즉 struct B : public A)에서 B의 가상 상속을 제거하면, 나는 단지 경고없이 오류가 발생합니다.

struct A 
{ 
    virtual void f() = 0; 
}; 

struct B : public virtual A 
{ 
    void f() {} 
}; 

class C : public B 
{}; 

struct D : public C, virtual B 
{}; 

int main() 
{ 
    return 0; 
} 

왜? 이것은 두려운 다이아몬드입니까?

+0

[다중 상속 가능한 중복 + 가상 함수 혼란] (http://stackoverflow.com/questions/616380/multiple-inheritance-virtual-function-mess) – Zeta

답변

3

그것은 왜냐하면 B에서 가상이 아닌 방법으로 C 상속 동안 B에서 가상 방식으로 D 상속합니다. 그러면 f() 두 개를 포함하여 B 두 번 나타납니다.

B의 가상 계승을 C에 시도해보십시오.

업데이트 : B에서 가상 상속을 제거하면 왜 작동합니까? A? 왜냐하면 "최종 재정의 자"가 변경되기 때문입니다. (B에서 f()의 최종 오버라이드) D의 가상 B에 한 번 C에서 (B에서 f()의 최종 오버라이드) 번 : A에서 BB에서 C 가상없이 당신은 A 두 번 있습니다. 당신이 AB에 가상 상속을 다시 추가하는 경우, A 한 번만 존재합니다 가상 B에서 한 번 C에서 한 번, BA에서 순수 f(), 모두를 구현하기 위해 경쟁이 개 최종 우선이있을 것이다.

해결 방법으로 using C::f; 또는 using B::fusing을 D에 추가 할 수 있습니다.

참조 C++ 10.3/2

+0

실제로 B를 상속 한 C가 실제로 문제를 해결합니다. 그러나 A에서 B의 가상 상속을 제거하면 결과에 어떤 영향을 미치는지 아직 알 수 없습니다. – Rai

+0

@ raai'B'로부터 사실상 상속받는다면'A'의 가상 상속은 더 이상 필요 없습니다. – Fozi

+0

예, 저는 그것이 사실이라고 믿습니다. 그러나 B가 더 이상 사실상 A로부터 상속하지 않을 때 오류가 사라지는 이유에 대한 질문에 여전히 대답하지 않습니다. – Rai

2

가의가에서 가상 상속 10.3[class.virtual]/2

A virtual member function C::vf of a class object S is a final overrider unless the most derived class of which S is a base class subobject (if any) declares or inherits another member function that overrides vf .

In a derived class, if a virtual member function of a base class subobject has more than one final overrider the program is ill-formed.

에서 '최종 overrider'의 정의를 살펴 보자, 거기에 A 형의 단 하나 개의 기본 클래스 하위 개체이며, 그것의 가상 멤버 함수 f()는 하나 이상의 최종 오버라이더를 갖는다. (타입 B의 각 서브 오브젝트에 하나씩)

A로부터의 가상 상속이 없다면, 타입 A의 두 개의 다른 기본 클래스 서브 오브젝트와 가상 멤버 함수 f) 각 h (각 B 하위 개체에 하나씩)

0

가상 기본 하위 개체는 전체 개체의 모든 기본 하위 개체간에 '공유'됩니다.

#include <iostream> 

struct A { 
    virtual void f() = 0; 
    virtual ~A() {} 
}; 

struct B : virtual A 
{ 
    void f() { std::cout << "B\n"; } 
}; 

struct C : virtual A 
{ 
    void f() { std::cout << "C\n"; } 
}; 

struct D : C, B {}; 

int main() { 
    D d; 
    A *a = dynamic_cast<A*>(&d); // single shared A between B and C 
    a->f(); // Should B::f() be called, or C::f()? 
} 

을 : A는 D : C : B와 D : B 사이에 공유되어 있기 때문에 그것의 f()이 고려 A::f().

에 대한 재정로 불리는이해야하는 B 객체 말할 수 없다 D의 B 및 C 기본 하위 객체는 모두 동일한 A 기본 하위 객체를 공유합니다. 우리가 A :: f()를 호출 할 때, 오버라이드 (override) 된 함수에 대해 가상 룩업 (look-up)이 수행된다. 그러나 B와 C는 모두이를 무시하려고 시도하고 있으므로 어느 것이 '이기는가'? x->f() "B"또는 "C"가 인쇄됩니까?대답은 상황에 부딪히는 프로그램이 잘못 형성되었다는 것입니다. 우리가함으로써 공유를 제거하면

B와 C는 각각의 기능은 고유 한 기본 클래스에 의해 재정의 한 비 사실상 다음 별도의베이스 하위 오브젝트를 상속 :

#include <iostream> 

struct A { 
    virtual void f() = 0; 
    virtual ~A() {} 
}; 

struct B : A 
{ 
    void f() { std::cout << "B\n"; } 
}; 

struct C : A 
{ 
    void f() { std::cout << "C\n"; } 
}; 

struct D : C, B {}; 

int main() { 
    D d; 
    // two different A objects 
    A *a1 = static_cast<A*>(static_cast<B*>(&d)); 
    A *a2 = static_cast<A*>(static_cast<C*>(&d)); 
    a1->f(); 
    a2->f(); 
}