在继承中,当实例化派生类(创建派生类obj)时,将第一个内存放在一边。在此之后,调用派生类构造函数。
class Base
{
public:
int m;
Base(int x=0)
: m(x)
{
}
};
class Derived: public Base
{
public:
double n;
Derived(double y=0.0)
: n(y)
{
}
};
在上面的例子中,当创建派生类对象时,调用派生类构造函数。
问题是,根据我的研究,在调用派生类构造函数之前调用基类构造函数。但是,派生类中的任何地方都没有显式指令来首先转到基类构造函数。编译器如何知道必须先执行基类构造函数????
我认为答案就是基类声明中的这一行:
class Derived: public Base
但是,问题是通过如下更改派生类,我们可以确保在派生构造函数体执行之前调用并初始化Base类构造函数。
class Derived: public Base
{
public:
double n;
Derived(double y=0.0, int z=0)
: Base(z), n(y)
{
}
};
所以,问题是在第一个例子中没有声明告诉基类构造函数首先被调用,但它实际上是先被调用,在第二个更改的例子中我告诉编译器首先转到基类构造函数。是不是已经知道首先转到基类构造函数?两个示例之间的执行有何不同,步骤是什么?
此致
答案 0 :(得分:3)
编译器知道调用Base类构造函数,因为您已指定通过语句继承Base:
class Derived : public Base
无论如何,编译器将在调用Derived的构造函数之前实例化(即调用构造函数)Base类。它也是为了正确构造派生类。
在初始化列表中声明:Base(z)
的第二个示例中,您告诉编译器使用此构造函数显式调用/初始化Base类。如果未通过初始化列表指定构造函数,编译器将始终调用默认构造函数。在初始化列表中指定正确的构造函数(即使它是默认值)被认为是最佳实践。
答案 1 :(得分:1)
如果你有一个Ball并从中派生出一个RedBall然后创建一个RedBall,你需要的第一件事是Ball,然后你可以把它涂成红色。
因此,要在您的示例中创建Derived类型的Object,您需要从Base类型的对象开始,然后从中构造Derived。因此,即使您没有显式调用基类的构造函数,编译器也知道它必须这样做。这条线
class Derived: public Base
实际上是通知编译器的指令。
在第二种情况下,你是明确的。这可以在你想要调用具有参数的基类的构造函数的情况下使用。
答案 2 :(得分:0)
在第一个示例中,您调用默认构造函数。在第二个示例中,您使用parametar
调用构造函数答案 3 :(得分:0)
两个示例之间的执行有何不同,步骤是什么?
不同之处在于,在第一种情况下,将调用DEFAULT构造函数,而在第二种情况下,将调用您已选择的构造函数。
答案 4 :(得分:0)
我认为误解是C ++语言以某种方式逐步解释,否则我无法解释“编译器是否已经调用了基类构造函数并在它看到派生调用之前对其进行了初始化类构造函数“。
情况并非如此,基本上编译器在开始生成输出之前“看到”所有编译单元。如果它看到你已经对一个特定的构造函数进行了显式调用 - 在你的情况下通过Base(z),它将在创建Derived对象时调用该构造函数。否则它将调用Base的默认构造函数。
最好不要将基础构造函数声明为Base(int x = 0)。尝试创建一个无参数构造函数和Base(int)一个,并在每个构造函数中放置一个断点,以确切地查看调用哪一个。 (或者,在Base(int x = 0)中放置一个断点并检查x的值......)