2

考虑以下代码:

class A {
public:
    int a;
};

class B : public A {
public:
    B() { std::cout << "B[" << a << "]" << std::endl; }
};

class C : public B {
public:
    C() { std::cout << "C[" << a << "]" << std::endl; }
};

int main(int argc, char *argv[]) {

    B();
    std::cout << std::endl;
    C();

}

及其输出——用 g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3 编译的程序:

B[0]

B[-2097962768]
C[-2097962768]

我发现获得第二次调用的唯一方法C()——初始化其值是向构造函数添加显式调用,例如:

class B : public A {
public:
    B() : A() { std::cout << "B[" << a << "]" << std::endl; }
};

class C : public B {
public:
    C() : B() { std::cout << "C[" << a << "]" << std::endl; }
};

尽管我知道调用每个以前的类的默认构造函数都会初始化这些值,但是当没有指定任何内容时,我无法看到正在调用的内容。

默认构造函数不是默认调用的 - 因此它的句柄?

4

2 回答 2

6

使用您的原始代码

class A {
public:
    int a;
};

class B : public A {
public:
    B() { std::cout << "B[" << a << "]" << std::endl; }
};

的成员A未初始化,因为您尚未指定任何初始化。通常,在 C++ 中,您不需要为不需要的东西付费。因此,默认情况下,您不会为 POD 成员获取初始化(但是,您会为具有构造函数的成员获取它,因为那里指定了初始化)。

在您随后的“显式构造函数调用”代码中

class B : public A {
public:
    B() : A() { std::cout << "B[" << a << "]" << std::endl; }
};

您已指定基类子对象的值初始化。A这有效地减少了零初始化。

和这个区别是一样的

A* p = new A;

相对

A* p = new A();

后一个值初始化对象。


标准…

C++11 §8.5/10
“初始化器为空括号集的对象,即 ,()应进行值初始化。”

C++11 §8.5./7
“对类型对象进行值初始化T意味着:
- 如果T是具有用户提供的构造函数 (12.1) 的(可能是 cv 限定的)类类型(第 9 条),则默认调用构造函数(如果没有可访问T的默认构造函数,则初始化格式错误); — 如果是(可能是 cv 限定的)非联合类类型,没有用户提供的构造函数,则该对象是零初始化的,如果 T 的隐式声明的默认构造函数是非平凡的,则调用该构造函数。 — 如果是数组类型,则每个元素都是值初始化的; — 否则,对象被零初始化。T
T
T

值初始化的对象被认为是已构造的,因此受制于适用于“构造的”对象、“构造函数已完成的对象”等的本国际标准的规定,即使没有为对象的构造函数调用构造函数。初始化。”

可能值得注意的是,值初始化不是原始 C++98 的一部分。它是由 Andrew Koenig(以“Koenig 查找”闻名)在 C++03 中引入的,目的是处理一些纯默认初始化的意外影响的严重问题。这就是()初始化程序在 C++98 中给你买的东西。

于 2013-02-26T15:48:02.777 回答
3

编辑我原来的答案是完全错误的,所以我对它进行了大量编辑。

如果要保证A::a在没有值初始化调用的情况下是零初始化的,例如

A a1; //

或者

B() { .... }

然后你可以给A一个构造函数并在那里进行初始化:

class A {
public:
  A() : a() {} // value initialization of a, means zero initialization here.
    int a;
};

否则,显式调用andA()的构造函数执行值初始化。BC

// value initialization of A sub-object leads to zero initialization of A::a
 B() : A() {} 

A这也适用于实例的初始化:

A a1 = A();
于 2013-02-26T15:31:45.380 回答