struct A {
virtual void foo() { std::cout << "a";};
};
struct B:public virtual A {
void foo() { std::cout << "b";}
};
struct C:public virtual A {
void foo() { std::cout << "c";}
};
struct D:public B, public C {
};
int main() {
return 0;
}
因此编译时这个给出了以下错误:
\main.cpp:16:8: error: no unique final overrider for 'virtual void A::foo()' in 'D'
struct D:public B, public C {
如果我们将B和C结构的继承非虚拟化,代码正在编译恰到好处而没有任何错误(但当然如果我们调用dd.foo会发生错误( ))。那有什么区别?为什么我们在虚拟地继承我们的类时会出现错误,如果我们直接进行操作就没有错误?
答案 0 :(得分:4)
使A
虚拟基类B
和C
确保D
只包含一个A
子对象 [1] 。为此,B
和C
都为foo
[2] 提供了最终覆盖,两者都由D
继承[2] ,因此D
有foo
的两个最终覆盖,使程序格式错误 [2] 。
当A
不虚拟基类B
和C
时,D
将包含两个不同的A
子对象 [1] 。这些子对象中的每一个都将拥有自己继承的foo
[2] 的最终覆盖。
[1]:N4140§10.1[class.mi] / 4:
不包含关键字virtual的基类说明符指定非虚基类。包含关键字virtual的基类说明符指定虚拟基类。对于每个不同的事件 在最派生类的类点阵中的非虚基类,最派生的对象应包含该类型的相应的不同基类子对象。对于指定为virtual的每个不同的基类,最派生的对象应包含该类型的单个基类子对象。
[2]:§10.3[class.virtual] / 2(强调我的):
如果虚拟成员函数vf在类Base和Derived中直接或间接派生的类中声明,则具有相同名称的成员函数vf,parameter-type-list,cv-qualification和ref-声明Base :: vf的限定符(或不存在),然后 Derived :: vf也是虚拟的(无论是否如此声明)并且它会覆盖Base :: vf。为方便起见我们说任何虚函数都会覆盖自己。 类对象S的虚拟成员函数C :: vf是最终覆盖,除非S是基类子对象(如果有)的最派生类声明或继承覆盖vf的另一个成员函数。在派生类中,如果基类子对象的虚拟成员函数具有多个最终覆盖,则程序格式不正确。