C ++继承初始化列表

时间:2013-07-24 16:39:57

标签: c++ inheritance

我对C++不熟悉,但我来自Java背景,因此我了解了大多数OOP概念。我正在阅读介绍性指南,我遇到了这个例子:

[Foo.H] 
class A
{
    public:
       A(int something);
};

class B : public A
{
    public:
       B(int something);
};

[Foo.C] 
#include "Foo.H"

A::A(int something)
{
    printf("Something = %d\n", something);
}

B::B(int something) : A(something)
{
}

假设通过将A(something)传递给B::B(int something)的初始化列表,它与java中的super关键字类似 - 也就是说,它将执行{{1}我的代码?另外,为什么我只从initalizer列表中调用A::A(int something)而不是A(something)

基本上我在问:以上是否相当于:

A::A(something)

让我扩展为什么我感到困惑。

如果我要使用:

B::B(int something)
{
    A::A(something)
}

通过

调用代码
B::B(int something) : A(something)
{
    int x = 5;
    printf("x = %d", x);
}

这会先打印B::B(7); 还是x = 5?为什么它会按此顺序执行?

我只是对语法感到有点困惑,这使得即使在这个简单的例子中也很难掌握和可视化继承。

3 个答案:

答案 0 :(得分:2)

是的,A(something)传递的值与super非常相似。您不必使用A::A,因为该语言会自动将基类名称注入子类。

但它并不等同于

B::B(int something)
{
    A::A(something)
}

因为那不是合法代码。您只能在初始化列表中选择要调用的父构造函数。

至于你关于印刷的问题......你试过吗?您会看到父something=首先打印后跟x=

答案 1 :(得分:1)

不,它们不等同

子类的构造函数将调用其父类的默认构造函数,除非您在初始化列表中明确地告诉它。

B::B( int something ) {}将隐式调用A::A(),如果A没有默认构造函数,则无法编译。

B::B(int something)
{
    A::A(something)
}

这样做是因为它试图在初始化列表中隐式调用A::A(),然后调用A::A(something),因为你知道它不会编译,因为A没有默认构造函数。

所以如果你想调用不同的父构造函数,那么唯一的方法就是在初始化列表中进行调用

B::B(int something) : A(something) {}

答案 2 :(得分:1)

A::A(int something)
{
    printf("Something = %d\n", something);
}

这是B的构造函数。构造函数所做的第一件事是构造它的基类(按类中声明的顺序,而不是构造函数的顺序),然​​后构造成员对象(按照声明的顺序)在类中,而不是在构造函数的顺序),然​​后它执行主体({}中的代码)。这样做的原因是因为B A个对象,所以它必须是完整的A才能开始成为B 1}}对象。并且在执行任何成员函数的代码之前必须完全构造所有成员,否则可能发生不好的事情。因此,必须在构造函数体开始之前构造基类和成员。

如果要更改基类或成员的初始化方式(例如,传递整数而不是默认构造),可以将其放在初始化列表中:

B::B(int something) : A(something)
{
    int x = 5;
    printf("x = %d", x);
}

您不必限定A的构造函数的名称,因为我们已经在对象B的上下文中,并且B已经知道A 1}}。

B::B(int something)
{
    A::A(something)
}

此代码无效,因为B会在A中执行正文之前构建它的{}对象。由于已经构造了A,因此在正文中调用A::A是没有意义的,编译器将对此进行诊断。

B::B(int something) : A(something)
{
    int x = 5;
    printf("x = %d", x);
}

如前所述,在构造B时,它首先构造基类,然后构造成员,然后执行主体。因此你会看到

something = 7
x = 5