C++标准中虚基类构造函数的调用规则是什么?
C++虚基类构造函数调用规则解析
先看这段可正常编译的代码:
struct Grandpa { Grandpa(int x) {} }; struct Dad : Grandpa { Dad(int y) : Grandpa(15) {} }; struct Son : Dad { Son(int z) : Dad(z) {} }; int main () { Son s(10); }
但如果把Grandpa设为Dad的虚基类,代码就会编译失败:
struct Grandpa { Grandpa(int x) {} }; struct Dad : virtual Grandpa { Dad(int y) : Grandpa(15) {} }; struct Son : Dad { Son(int z) : Dad(z) {} }; int main () { Son s(10); }
报错信息如下:
example.cpp: In constructor ‘Son::Son(int)’: example.cpp:12:27: error: no matching function for call to ‘Grandpa::Grandpa()’ 12 | Son(int z) : Dad(z) {}
问题:根据C++标准,虚基类构造函数的调用规则是什么?
核心调用规则(基于C++标准)
虚基类的构造逻辑和普通继承差异很大,关键规则总结如下:
最终派生类全权负责虚基类初始化
在包含虚基类的继承链中,只有最底层的最终派生类(比如例子里的Son)有权调用虚基类的构造函数。中间基类(比如Dad)对虚基类的构造调用会被编译器直接忽略——这是为了避免虚基类被多次初始化(毕竟虚基类在内存中只有一份实例)。无默认构造时必须显式初始化
如果虚基类没有默认构造函数(比如Grandpa只提供了带int参数的构造),最终派生类必须在自己的构造函数初始化列表中显式指定虚基类的构造方式。否则编译器会尝试调用不存在的默认构造,直接触发编译错误。修正例子中的代码,只需让
Son直接初始化Grandpa即可:struct Son : Dad { Son(int z) : Grandpa(z), Dad(z) {} // 显式调用虚基类构造 };虚基类构造优先级最高
无论虚基类在继承体系中的位置如何,它的构造函数都会在所有非虚基类、成员对象的构造函数之前执行,确保虚基类的状态先被正确初始化。普通基类的构造规则不变
非虚基类的构造仍由直接继承它的类负责,不受虚基类规则影响——比如例子里Dad对Grandpa的构造调用,在非虚继承时有效,虚继承时就被忽略了。
内容的提问来源于stack exchange,提问作者blonded04
相关产品推荐
相关产品推荐

