3

我很新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)类似于superjava 中的关键字是否正确——也就是说,它将执行A::A(int something)'s 代码?另外,为什么我只调用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还是something = 7先打印出来?为什么它会按这个顺序执行?

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

4

3 回答 3

2

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

然而,它不等同于

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

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

至于你关于打印的问题……你试过了吗?您会看到父something=打印件首先打印,然后是x=.

于 2013-07-24T16:48:51.780 回答
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) {}
于 2013-07-24T16:52:13.467 回答
1
A::A(int something)
{
    printf("Something = %d\n", something);
}

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

如果你想改变基类或成员的初始化方式(例如传递一个整数而不是默认构造),你可以把它放在初始化列表中:

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

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

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

这段代码是无效的,因为B. 由于已经构建,因此在主体中调用没有意义,编译器将对此进行诊断。A{}AA::A

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

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

something = 7
x = 5
于 2013-07-24T17:03:39.230 回答