默认成员初始化器(default member initializer)是C++11的一个构造,允许在类成员变量声明时直接声明默认值。这一特性常常与其他数据初始化方法混淆。
早期的C++不允许在声明时初始化成员;值只能在构造函数内部(主体或初始化列表)中赋值。引入默认成员初始化器(C++11)改善了可读性,并减少了不确定初始化导致的错误风险。
如果字段未被显式初始化,包含的是“垃圾”(不确定)值。在构造函数内部赋值的效率低于初始化列表,而忽略默认成员初始化器则使类的扩展和新构造的创建变得复杂。
对于简单的值,使用默认成员初始化器;对于复杂情况(特别是需要依赖或非标准值时),使用构造函数的初始化列表。
代码示例:
class Widget { int x = 42; // 默认成员初始化器 std::string name = "default"; // 默认成员初始化器 public: Widget() = default; // x=42, name="default" Widget(int xx) : x(xx), name("new") {}// x=xx, name="new" };
关键特性:
如果一个成员在构造函数主体内初始化,但不在初始化列表中,默认成员初始化器会生效吗?
答案:
不会。如果没有在初始化列表中指定,变量首先会被默认值初始化(默认成员初始化器),然后在构造函数主体中进行赋值,这样效率较低。
具有默认成员初始化器的类成员在继承时的初始化顺序是什么?
答案:
首先初始化基类成员,然后是派生类成员;对于每个具有默认成员初始化器的成员,首先会使用初始化列表(如果指定),然后使用默认成员初始化器,否则将保持未初始化状态(对于POD)。不会发生“双重初始化”。
默认成员初始化器可以适用于类的静态成员吗?
答案:
不,静态成员不能通过默认成员初始化器初始化。它们需要在类外部或通过C++17的内联静态初始化。
示例:
struct S { static int a = 5; // 错误! };
一个动态字符串的类,在某些构造函数中忘记初始化。后来调用时会导致未定义行为。
优点:
缺点:
所有字段都是默认成员初始化器。额外的构造函数在必要时通过初始化列表显式初始化所需成员。
优点:
缺点: