派生类构造函数中显式调用基类构造函数必须在初始化列表中进行,语法为: Base(arg1, arg2),紧随参数列表之后、函数体之前;不能在函数体内用Base::Base(...)调用,否则被视作定义新对象而编译报错;调用顺序由继承声明顺序决定,与初始化列表书写顺序无关;虚基类构造函数必须由最派生类在初始化列表中显式调用,否则将尝试调用其默认构造函数,若不存在则编译失败。

派生类构造函数里怎么显式调用基类构造函数
必须在派生类构造函数的初始化列表中调用,不能在函数体里用 Base::Base(...) 这种写法——那会被当成定义新对象,编译直接报错。
- 语法是
: Base(arg1, arg2),紧跟在派生类构造函数参数列表后、函数体前 - 如果基类有多个构造函数,选哪个取决于你传的参数类型和个数,编译器不会自动帮你选默认构造函数(除非你显式写
: Base()) - 如果基类没有默认构造函数,而你又没在初始化列表里调用它,编译器会报错:
no matching function for call to 'Base::Base()'
基类构造函数调用顺序不可更改
基类构造函数总是在派生类构造函数体执行之前运行,且按继承声明顺序(不是初始化列表顺序)调用。比如 class D : public A, public B,那么一定是先调 A::A(),再 B::B(),哪怕你在初始化列表里写成 : B(), A() 也没用。
- 成员变量的初始化顺序也遵循声明顺序,和初始化列表书写顺序无关——这点容易和基类调用混淆
- 如果基类构造函数依赖某个派生类成员(比如传入一个成员变量),不行:那个成员此时还没构造,值是未定义的
虚继承下基类构造函数由谁负责调用
最派生类(即最终 new 出来的那个类)必须显式调用虚基类的构造函数,否则即使中间类写了,也会被忽略。
- 例如
class A是虚基类,B : virtual A,C : virtual A,D : B, C,那么只有D的构造函数初始化列表里写: A(...)才有效 - 如果
D没写,编译器会尝试调A的默认构造函数;若不存在,默认构造失败,报错call to implicitly-deleted default constructor -
B和C构造函数里写的: A(...)在虚继承下会被忽略
初始化列表里调用基类构造函数时参数怎么来
参数可以是构造函数参数、常量、全局变量、静态成员,但不能是尚未初始化的当前类成员变量。
立即学习“C++免费学习笔记(深入)”;
- 错误写法:
D(int x) : base_member(x), base(base_member) { }——base_member此时尚未初始化,base构造时用的是垃圾值 - 正确做法是把逻辑前置:要么把计算提前到参数层面(比如加一个辅助函数),要么改用委托构造(C++11起支持),例如
D(int x) : D(x * 2, "default") { } - 注意:const 成员或引用成员也必须在初始化列表里赋值,它们和基类构造一样,没机会在函数体里“赋值”
实际写的时候最容易漏掉虚基类的显式调用,或者误以为初始化列表顺序决定构造顺序——这两处一错,轻则行为未定义,重则编译不过。


















