面试题答案
一键面试区别
- 初始化顺序:
- 初始化列表:按照成员变量在类中声明的顺序进行初始化,而不是按照初始化列表中出现的顺序。
- 构造函数体:先调用成员变量的默认构造函数进行初始化(如果没有在初始化列表中初始化),然后在构造函数体内对成员变量进行赋值操作。
- 性能:
- 初始化列表:对于一些对象成员,直接初始化可能效率更高,因为避免了先默认构造再赋值的过程。例如对于
const
成员变量和引用成员变量,必须使用初始化列表初始化,因为它们不能被赋值。 - 构造函数体:由于存在先默认构造再赋值的过程,对于一些复杂对象,可能会有额外的性能开销。
- 初始化列表:对于一些对象成员,直接初始化可能效率更高,因为避免了先默认构造再赋值的过程。例如对于
- 适用场景:
- 初始化列表:适用于
const
成员变量、引用成员变量的初始化,以及对象成员初始化希望直接构造而非先默认构造再赋值的场景。 - 构造函数体:适用于简单的基本数据类型成员变量的赋值操作,在不需要考虑性能优化或者初始化逻辑比较复杂,需要在构造函数体中进行一些条件判断等操作时使用。
- 初始化列表:适用于
示例说明初始化列表优势场景
#include <iostream>
#include <string>
class Data {
public:
Data(int value) : num(value) {
std::cout << "Data constructor with value: " << num << std::endl;
}
~Data() {
std::cout << "Data destructor" << std::endl;
}
private:
int num;
};
class MyClass {
public:
// 使用初始化列表初始化const成员变量和对象成员
MyClass(int val, const std::string& str) : constVar(val), data(val), strObj(str) {
std::cout << "MyClass constructor" << std::endl;
}
// 错误示例,如果在构造函数体中初始化constVar会报错
// MyClass(int val, const std::string& str) {
// constVar = val; // 错误,const变量不能被赋值
// data = Data(val); // 先默认构造data,再赋值,效率低
// strObj = str;
// }
private:
const int constVar;
Data data;
std::string strObj;
};
int main() {
MyClass obj(10, "Hello");
return 0;
}
在上述示例中,MyClass
类中有const
成员变量constVar
,必须在初始化列表中初始化。Data
类型的对象成员data
如果在构造函数体中赋值,会先默认构造data
,然后再赋值,使用初始化列表可以直接构造data
,提高效率。所以在这些场景下,使用初始化列表更具优势。