Uti*_*eev 5 c++ virtual inheritance virtual-inheritance
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;
}
Run Code Online (Sandbox Code Playgroud)
因此,在编译时会出现以下错误:
\main.cpp:16:8: error: no unique final overrider for 'virtual void A::foo()' in 'D'
struct D:public B, public C {
Run Code Online (Sandbox Code Playgroud)
如果我们将B和C结构的继承设为非虚拟的,则代码将正确编译而没有任何错误(但是,如果我们调用dd.foo(),则错误当然会发生)。那有什么区别呢?为什么当我们虚拟继承我们的类时出现错误,而如果直接继承则没有错误呢?
制作 和的虚拟基类A,确保它恰好包含一个子对象[1]。为此, 和 都为[2]提供最终重写器,并且都由[2]继承,因此有两个最终重写器,使得程序格式不正确[2]。BCDABCfooDDfoo
当A不是和的虚拟基类时,将包含两个不同的子对象[1]。这些子对象中的每一个都会有自己继承的[2]最终重写器。BCDAfoo
[1]: N4140 \xc2\xa710.1 [class.mi]/4:
\n\n\n\n\n不包含关键字 virtual 的基类说明符指定非虚拟基类。包含关键字 virtual 的基类说明符指定虚拟基类。对于最派生类的类格中非虚拟基类的每次不同出现,最派生对象应包含该类型的对应的不同基类子对象。对于指定为 virtual 的每个不同基类,最派生的对象应包含该类型的单个基类子对象。
\n
[2]: \xc2\xa710.3 [class.virtual]/2 (强调我的):
\n\n\n\n如果在类 Base 和直接或间接从 Base 派生的类 Derived 中声明了虚拟成员函数 vf,则成员函数 vf 具有相同的名称、parameter-type-list、cv-qualification 和 ref-qualifier(或如果声明了 Base::vf,则Derived::vf 也是虚拟的(无论是否如此声明),并且它会覆盖 Base::vf。为了方便起见,我们说任何虚函数都会覆盖自身。类对象 S 的虚拟成员函数 C::vf 是最终重写者,除非 S 是基类子对象(如果有)的最底层派生类声明或继承了另一个重写 vf 的成员函数。在派生类中,如果基类子对象的虚拟成员函数具有多个最终重写程序,则程序格式错误。
\n