构造函数调用继承的类

Rub*_*ens 2 c++ constructor default initialization default-constructor

请考虑以下代码:

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();

}
Run Code Online (Sandbox Code Playgroud)

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

B[0]

B[-2097962768]
C[-2097962768]
Run Code Online (Sandbox Code Playgroud)

我发现获得第二个调用的唯一方法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; }
};
Run Code Online (Sandbox Code Playgroud)

虽然我知道调用每个前一个类的默认构造函数会初始化值,但是当没有指定任何内容时,我无法看到被调用的内容.

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

Che*_*Alf 6

使用您的原始代码

class A {
public:
    int a;
};

class B : public A {
public:
    B() { std::cout << "B[" << a << "]" << std::endl; }
};
Run Code Online (Sandbox Code Playgroud)

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

在随后的"显式构造函数调用"代码中

class B : public A {
public:
    B() : A() { std::cout << "B[" << a << "]" << std::endl; }
};
Run Code Online (Sandbox Code Playgroud)

您指定的值初始化了的A基类子对象.实际上,这减少到零初始化.

这与以下相同

A* p = new A;
Run Code Online (Sandbox Code Playgroud)

A* p = new A();
Run Code Online (Sandbox Code Playgroud)

后者值初始化对象.


Standardese ...

C++11§8.5/ 10:
"一个对象,其初始化器是一组空的括号,即(),应该进行值初始化."

C++11§8.5./7:
" 对类型对象进行值初始化T意味着:
- 如果T是具有用户提供的构造函数(12.1)的(可能是cv限定的)类类型(第9节),则默认T调用构造函数(如果T没有可访问的默认构造函数,则初始化是错误的);
- 如果T是没有用户提供的构造函数的(可能是cv限定的)非联合类类型,则该对象是零初始化的,并且如果T的隐式声明的默认构造函数是非平凡的,则调用该构造函数.
- 如果T是数组类型,则每个元素都是值初始化的;
- 否则,对象被零初始化.
值初始化的对象被视为构造,因此受本国际标准的规定适用于"构造"对象,"构造函数已完成的对象"等,即使没有为该对象调用构造函数也是如此.初始化."

值得注意的是,值初始化不是原始C++ 98的一部分.它是在C++ 03中由Andrew Koenig("Koenig查找"成名)引入的,以便处理纯默认初始化的意外影响的一些严重问题.这是()初始化程序在C++ 98中为您提供的内容.