我有一个名为MyBase的类,它有一个构造函数和析构函数:
class MyBase
{
public:
MyBase(void);
~MyBase(void);
};
我有一个名为Banana的类,它扩展了MyBase,如下所示:
class Banana:public MyBase
{
public:
Banana(void);
~Banana(void);
};
Banana中新构造函数和析构函数的实现是否覆盖了MyBase,或者它们是否仍然存在,并且在Banana构造函数/析构函数执行之前或之后被调用?
谢谢,如果我的问题看起来很愚蠢,我很抱歉。
答案 0 :(得分:16)
始终在派生构造函数之前调用Base构造函数。 将在Dervided析构函数之后调用Base析构函数。
您可以在派生构造函数上指定所需的Base构造函数,否则将执行默认构造函数。
如果您定义了其他构造函数但不是默认构造函数,并且未在Derived构造函数上指定要执行哪个构造函数,那么请尝试使用不存在的默认值,这将导致编译失败。
上述情况发生是因为一旦声明了一个构造函数,就不会生成默认构造函数。
答案 1 :(得分:8)
无法覆盖构造函数。您不能在派生类中声明基类构造函数。类构造函数必须在其他任何内容之前调用基类中的构造函数(如果未明确声明,则调用默认构造函数)。
为了能够正确地清理派生类,您应该将基类析构函数声明为virtual
:
virtual ~MyBase() { ... }
答案 2 :(得分:7)
应该说
class Banana : public MyBase
{
public:
Banana(void);
~Banana(void);
};
派生类的构造函数在基类的构造函数之后被调用。析构函数以相反的顺序被调用。
答案 3 :(得分:4)
构造函数在继承树中自上而下调用。这样,派生的构造函数可以在尝试使用基类的任何属性之前依赖于完全初始化的基础对象。
析构函数以与构造函数相反的顺序调用,出于同样的原因 - 派生类依赖于基类,但基类不依赖于派生类。
如果任何可能通过指向基类的指针销毁对象,则必须声明所有析构函数virtual
。
答案 4 :(得分:4)
构造函数和析构函数是特殊的成员函数。通常,您将在任何地方读取构造从最小派生类型开始,从层次结构一直到最派生类型。这实际上是构造函数执行完成的顺序,而不是构造的启动方式。
构造函数初始化列表执行顺序保证尽管最派生对象的构造函数将是第一个开始执行的构造函数,但它将是最后一个完成的构造函数
实例化对象时,首先调用与构造调用匹配的派生最多的构造函数。匹配的最多派生构造函数的初始化列表启动,初始化列表具有固定顺序:首先调用继承列表中按顺序或出现的基类的构造函数。然后按照它们在类声明中出现的顺序(而不是它们在初始化列表中出现的顺序)调用成员属性构造函数。在整个初始化列表(在每个级别)完成之后,执行构造函数体块,之后构造函数调用完成。
在最导出的析构函数完成执行后,将以相反的构造顺序调用所有基本析构函数。破坏按照与构造完全相反的顺序发生。
析构函数以不同的方式是特殊的:它们不能被覆盖。当您调用类的派生程度最高的析构函数时,它将完成析构函数体的执行,之后将按创建的相反顺序调用所有成员属性析构函数。在最派生的析构函数完成并完成了最派生对象的成员析构函数之后,其最直接基础的析构函数以相反的构造顺序开始,析构函数体将执行,然后成员属性析构函数等等。最后,所有构造的元素都将被销毁。
多态类的析构函数应该是虚拟的
上面的销毁描述从调用派生最多的析构函数开始。这可以通过在指向最派生类型的指针上调用delete
,当一个自动对象超出范围,或者当对象通过一个析构函数为虚拟的基类delete
来实现时。
如果忘记在基类中添加析构函数关键字并尝试通过指向基类的指针删除派生对象,则将直接调用基本析构函数,这意味着指针下面的所有子对象都在层次结构不会被正确销毁。通过指向基类型的指针删除对象的所有继承层次结构必须具有虚拟析构函数。作为一般的经验法则,如果您已经有任何虚拟方法,那么使析构函数虚拟化的成本可以忽略不计,并且是一个安全的网络。许多编码指南强制执行继承层次结构中的析构函数必须是虚拟的。有些人甚至要求所有析构函数都是虚拟的,这样做的目的是避免可能的资源泄漏,代价是为所有类型添加vtable和为所有对象添加vtable指针。
答案 5 :(得分:2)
您缺少继承类型:
更改
class Banana:MyBase
要:
class Banana: public MyBase
至于
执行新的 香蕉的构造函数和析构函数 覆盖MyBase,或者它们 仍然存在,并在之前得到称之为 或者在Banana构造函数之后/ 析构函数执行?
继承的顺序从下到上执行,这意味着将首先调用MyBase,然后调用Banana。如果你有另一个子类,它将被称为最后一个。
举个例子:
class RottenBanana : public Banana
继承链现在是RottenBanana - >香蕉 - > MyBase
这个类的构造函数将从MyBase开始调用,然后调用Banana,然后调用RottenBanana。
答案 6 :(得分:-2)
如果你实例化一个EEGModeRGB对象(附有三色led) - 然后立即删除它,你会看到蓝色,绿色,黄色和红色,每个一秒 - 按此顺序。
class EEGMode {
public:
EEGMode() { setAllPixelsToColor(BLUE); delay(1000); }
virtual ~EEGMode() { setAllPixelsToColor(RED); delay(1000); }
};
class EEGModeRGB : public EEGMode {
public:
EEGModeRGB() { setAllPixelsToColor(GREEN); delay(1000); }
virtual ~EEGModeRGB() { setAllPixelsToColor(YELLOW); delay(1000); }
};