Base class 成员初始化

Base class members initalization

为什么下面的代码不允许我初始化基 class 成员:

class A { 
public:
   int x;
};

class B : public A {
public:
    B() : x(0) {} // error
};

而以下情况:

class A { 
public:
   int x;
};

class B : public A {
public:
    B() { x = 0; } // ok
};

因为 base-class 被视为初始化列表中的成员。

您可以像这样描绘 B 类型的对象:

class C {
public:
    A parent;
};

在此示例中,您将无法初始化 parent.x,而只能初始化 parent。 即使您可以访问和修改正文中的 parent.x,就像您所做的那样,您也无法访问其在初始化列表中的成员:

C::C() {
    parent.x = 5; // Works
}

C::C() : parent.x(5) {} // Won't work

另一方面,如果您有 A 的构造函数,例如

A::A(int i): x(i) {}

,您可以在 C:

的初始化列表中使用此构造函数
C::C(): parent(5) {} // Works and does what you want

如果你有 A 的构造函数,你对 B 有相同的选择:

B::B(): A(5) {}

这段代码

class A { 
public:
   int x;
};

class B : public A {
public:
    B() : x(0) {} // error
};

不正确,因为根据 C++ 标准(12.6.2 初始化基类和成员)

2 在 mem-initializer-id 中,在构造函数的 class 范围内查找初始非限定标识符,如果在该范围内未找到,则在包含构造函数的范围内查找定义。 [ 注意:如果构造函数的 class 包含与 class 的直接或虚拟基 class 同名的成员,则命名该成员或基的 mem-initializer-id class 并由单个标识符组成,指的是 class 成员。可以使用限定名称指定隐藏基 class 的 mem-initializer-id。 — 尾注 ] 除非 mem-initializer-id 命名构造函数的 class,构造函数 class 的非静态数据成员,或者该构造函数的直接或虚拟基础 class,内存初始化器格式错误。

你可以这样写

class A { 
public:
   int x;
};

class B : public A {
public:
    B() : A{ 0 } {}
};

在 mem-initializer-list 中使用了直接基础 class 标识符。

注意这里用的是大括号A{ 0 }而不是圆括号,因为class A是一个聚合

在此代码段中

class A { 
public:
   int x;
};

class B : public A {
public:
    B() { x = 0; } // ok
};

数据成员x不在mem-initializer-list中,在默认初始化后在构造函数的主体中分配。那就是在构造函数的主体中使用了已创建对象的赋值运算符。