C++ 为什么GCC会给我一个错误:没有唯一的最终重写器?
在下面的代码中,我得到以下警告和错误:C++ 为什么GCC会给我一个错误:没有唯一的最终重写器?,c++,gcc,diamond-problem,C++,Gcc,Diamond Problem,在下面的代码中,我得到以下警告和错误: 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中删除B的虚拟继承(即结构B:public A),我只得到警告,没有错误 struct A { virtual void f() =
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中删除B的虚拟继承(即结构B:public A
),我只得到警告,没有错误
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;
}
为什么??这是可怕的钻石吗?这是因为
C
以非虚拟方式从B
继承,而D
以虚拟方式从B
继承。这将为您提供两次B
,包括两次f()
尝试在C
中虚拟继承B
更新:那么,当您从A
中删除B
中的虚拟继承时,为什么它会起作用呢?因为它更改了“最终重写器”。如果没有B
中的A
和C
中的B
中的A
两次:一次在C
中(最后覆盖B
中的f()
),一次在D
中的B
中的虚拟B
中(最后覆盖f()
)。如果将B
中的虚拟继承添加回A
,A
将只出现一次,并且将有两个最终覆盖竞争实现A
中的纯f()
,都在B
中,一个从C
中,一个从虚拟B
中
作为一种解决方法,您可以使用
向D添加一个,即使用C::f添加代码>或使用B::f
<参见C++ +33/2让我们看看“最终重写器”的定义,从<代码> 10.3 [类.Virtual] / 2
类对象S
的虚拟成员函数C::vf
是最终重写器,除非S
的最派生类是基类子对象(如果有)声明或继承另一个重写vf
的成员函数
在派生类中,如果基类子对象的虚拟成员函数具有多个最终重写器,则程序格式错误
对于A的虚拟继承,只有一个类型为A的基类子对象,其虚拟成员函数f()具有多个最终重写器(类型为B的每个子对象中有一个)
如果没有来自A的虚拟继承,则有两个不同类型A的基类子对象,它们的虚拟成员函数f()都有自己的最终重写器(每个B子对象中有一个)虚拟基子对象在完整对象中的所有基子对象之间“共享”。由于A在D::C::B和D::B之间共享,因此它无法判断哪个B对象应该调用其f()
作为A::f()的覆盖。
考虑:
#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()?
}
实际上从B继承C的可能的重复确实解决了这个问题。但是我仍然不明白为什么从A中删除B的虚拟继承会影响结果。@Rai如果你从B
中虚拟继承,那么你就不再需要从A
中虚拟继承了。是的,我相信这是真的。但是它仍然不能回答为什么当B不再从A继承时错误会消失的问题。@Rai好的,现在我知道你是从哪里来的了。请看我的更新。啊,现在我明白了,非常感谢。你和库比差不多在同一时间拿到的,不用投了。您可以显式消除歧义:d.A::f()代码>
#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();
}