构造函数调用继承的类

时间:2013-02-26 15:28:33

标签: c++ constructor initialization default 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();

}

它的输出程序用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; }
};

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

默认情况下不是默认构造函数 - 因此它的句柄?

2 个答案:

答案 0 :(得分: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();

后一个值 - 初始化对象。


... 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中为您提供的内容。

答案 1 :(得分:3)

编辑我的原始答案非常错误,因此我对其进行了大量编辑。

如果您想保证在没有值初始化调用(例如

)的情况下A::a被零初始化
A a1; //

B() { .... }

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

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

否则,在A()B的构造函数中显式调用C会执行值初始化。

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

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

A a1 = A();