面试题答案
一键面试性能方面
- 初始化成员列表:
- 对于类类型成员变量,初始化成员列表是直接调用成员变量的构造函数进行初始化。例如,假设有一个类
MyClass
包含一个std::string
成员变量str
:
class MyClass { private: std::string str; public: MyClass(const std::string& s) : str(s) {} };
- 这种方式效率较高,因为它避免了先默认构造成员变量,然后再在构造函数体中赋值的额外开销。在上述例子中,
str
直接使用传入的s
进行初始化,而不是先默认构造str
,再调用str
的赋值运算符。
- 对于类类型成员变量,初始化成员列表是直接调用成员变量的构造函数进行初始化。例如,假设有一个类
- 构造函数体中赋值:
- 对于类类型成员变量,会先调用成员变量的默认构造函数,然后在构造函数体中再调用赋值运算符进行赋值。例如:
class MyClass { private: std::string str; public: MyClass(const std::string& s) { str = s; } };
- 这种方式会产生额外的开销,因为先默认构造了
str
,然后又进行了一次赋值操作,性能相对初始化成员列表较差。
适用场景方面
- 初始化成员列表:
- 常量成员变量:常量成员变量必须在定义时初始化,所以只能使用初始化成员列表。例如:
class MyClass { private: const int num; public: MyClass(int n) : num(n) {} };
- 引用成员变量:引用成员变量也必须在定义时初始化,同样只能使用初始化成员列表。例如:
class MyClass { private: int& ref; public: MyClass(int& n) : ref(n) {} };
- 没有默认构造函数的类类型成员变量:如果类的成员变量没有默认构造函数,就无法在构造函数体中先默认构造再赋值,必须使用初始化成员列表。例如:
class NoDefaultConstructor { public: NoDefaultConstructor(int n); }; class MyClass { private: NoDefaultConstructor obj; public: MyClass(int n) : obj(n) {} };
- 构造函数体中赋值:
- 当成员变量的初始化逻辑非常复杂,需要在构造函数体中进行一些计算或者条件判断后再赋值时,构造函数体中赋值可能更合适。例如:
class MyClass { private: int num; public: MyClass(int a, int b) { if (a > b) { num = a; } else { num = b; } } };
- 在这种情况下,使用初始化成员列表会使代码变得复杂,而在构造函数体中进行赋值则更直观和易读。