C++中类无默认构造函数时为何必须用构造函数初始化列表?含性能疑问
嘿,这两个问题都是C++里关于构造函数初始化的经典点,我来给你捋明白:
1. 为什么类没有默认构造函数时必须用构造函数初始化列表?
简单来说:没有默认构造函数的类,没法被"默认创建"——必须显式传参调用它的有参构造。
如果不用初始化列表,而是在构造函数体里给成员赋值,编译器的执行逻辑是这样的:先尝试用默认构造函数创建这个成员对象,然后再在构造函数体里给它赋值。但问题是这个类根本没有默认构造函数,编译器找不到可以调用的默认构造来完成第一步的对象创建,直接就会编译报错。
举个直白的例子:假设你有个类A只有A(int)这个构造函数,如果你在类B里把A当成员,写B() { a = A(5); }——这时候编译器会先试图默认构造a,但A没默认构造,直接就给你报错。只有用初始化列表B() : a(5) {},才能跳过默认构造的步骤,直接调用A的有参构造来初始化a。
2. 基类/成员类无默认构造时必须用初始化列表的原因,以及是否有性能提升?
为什么必须用初始化列表?
C++里对象的初始化顺序是铁律:先初始化基类,再初始化成员对象,最后执行构造函数体。
如果基类A没有默认构造函数,那创建子类B的对象时,必须在B的构造函数初始化阶段就调用A的有参构造——因为基类的初始化要在子类构造函数体执行之前完成,你根本没法在构造函数体里去"补"基类的初始化(这时候编译器已经尝试过默认构造基类,早就报错了)。
成员对象也是同样的道理:成员对象的初始化发生在构造函数体执行之前,所以必须在初始化列表里调用它的有参构造,不然编译器还是会尝试默认构造,直接报错。
有没有性能提升?
必须有!而且对于复杂对象来说提升还挺明显。
如果不用初始化列表,编译器会先默认构造成员/基类对象(假设能默认构造的话),然后再在构造函数体里赋值——这相当于做了两次操作:构造+赋值。而用初始化列表的话,直接一步完成构造和初始化,少了一次赋值的开销。
比如对于那些带动态内存分配的类、或者拷贝/赋值开销很大的类(比如std::string、自定义的大对象),少一次赋值操作能省不少时间和资源。
代码示例
#include <iostream> using namespace std; class A { int i; public: A(int); }; A::A(int arg) { i = arg; cout << "A's Constructor called: Value of i: " << i << endl; } // Class B is derived from A class B : public A { public: // 必须用初始化列表调用A的有参构造,否则编译报错 B(int val) : A(val) { cout << "B's Constructor called" << endl; } }; // Class C contains A as a member class C { A a; public: // 必须用初始化列表初始化成员a,否则编译报错 C(int val) : a(val) { cout << "C's Constructor called" << endl; } }; int main() { B b(10); C c(20); return 0; }
运行这段代码会输出:
A's Constructor called: Value of i: 10 B's Constructor called A's Constructor called: Value of i: 20 C's Constructor called
能清楚看到初始化顺序是先基类/成员,再子类/包含类的构造函数体。
内容的提问来源于stack exchange,提问作者Pramod

