我有点困惑,我正在阅读这个C++ Constructor/Destructor inheritance,所以它说构造函数和析构函数不是从基类继承到派生类,而是在创建派生对象时调用构造函数和析构函数。那么继承类的基类数据成员的构造函数和析构函数是什么?
答案 0 :(得分:4)
建造者和破坏者是非常特殊的动物;事实上,标准将它们标识为“特殊成员函数”。
关于构造函数和析构函数的所有奇怪和独特的东西(例如,它们没有“名称”这一事实以及它们不是“继承”的事实)几乎与所有编程无关和程序员。以下是您需要了解的内容:
构造函数和析构函数不是成员变量(显然) - 它们是(特殊)成员函数。
从基类派生时,将调用基类的某些构造函数。 哪个构造函数取决于您编写代码的方式。如果未明确指定要调用的构造函数,则将调用默认构造函数。这发生在派生对象的初始化列表中,即使您还没有编写过。
您可以通过初始化列表指定另一个构造函数:
class Bar : public Foo
{
public:
Bar()
:
Foo (1, 2, 3)
{
}
};
这里,Bar
的初始化列表指定了Foo
上的构造函数,它带有3个可从积分转换的参数。一个这样的构造函数可能是:
class Foo
{
public:
Foo (int a, long b, unsigned c)
:
mA (a),
mB (b),
mC (c)
{
}
private:
int mA;
long mB;
unsigned mC;
};
返回上面的Bar
示例。当初始化列表执行完毕,并且在Bar
的构造函数体开始之前,{strong>所有的Bar
基类和成员变量都有已经实例化并初始化。这就是为什么除了默认构造函数之外为Foo
指定一些构造函数的唯一方法是通过初始化列表 - 这反过来又是必须具有初始化列表的原因。基类没有可用的默认构造函数。
问题:如果没有继承构造函数和析构函数,那么为什么在实例化派生类型时会调用它们?
答案:因为构造函数是初始化对象,并且派生类型与基类型具有IS-A关系。
再次考虑上面的Foo
和Bar
。 Bar
来自Foo
,因此在某种意义上Bar
是A Bar
。它不仅仅是Foo
,还有Foo
没有的东西;但它拥有所有Foo
- ness。由于Bar
对象部分属于Foo
,因此必须初始化Foo
- Foo
。由于所有初始化ob对象都是通过构造函数完成的,因此必须调用Foo
的构造函数。
因此,构造函数和析构函数在重载意义上不是继承的 - 但是将调用基类的构造函数。他们必须是。否则,Bar
对象的class Foo
{
public:
std::string mS;
};
class Bar : public Foo
{
public:
long mArray[0xFFFF]; // an array of 65K longs
};
int main()
{
Foo* thingy = new Bar; // Totally OK
// ... do stuff...
delete thingy; // WHOOPS! Memory leak!
}
可能永远不会出现。
当您从基类派生时,您经常要做的事情是传递指向基类的指针。实际上,在许多情况下,您可能根本不需要指向派生类型的指针。在设计抽象接口时尤其如此。
当你这样做并且没有采取所有必要的准备工作时,会出现一个令人讨厌的问题。考虑:
delete
在Foo
调用中,我们通过基类指针删除。 Bar
析构函数(隐式)被正确调用,但Foo
析构函数不是 - 留下大量65K长的漏洞。
要解决此问题,我们需要virtual
一个class Foo
{
public:
std::string mS;
virtual ~Foo() {}
};
析构函数:
virtual
这没什么用,但它做了一件重要的事情:它设置了多态性,这样当我们调用析构函数(隐式)时,将调用虚拟覆盖。
这是设计类层次结构时的关键步骤。如果您认为人们有可能将指针传递给基类,那么基类中应该有一个virtual
析构函数。事实上,我建议几乎在每种情况下你都应该有{{1}}析构函数,即使你不认为人们会这样使用它。
答案 1 :(得分:3)
没有。正如你所说,构造函数和析构函数不是继承的(顺便说一句,赋值运算符也不是)。如果它们是遗传的,那将是逻辑上的缺陷,对吧?构造函数(和析构函数)特定于该类;并且因为派生类通常具有特定的和新的,所以基础构造函数不足以初始化继承的类对象。
那么为什么在创建子类的对象时调用基础构造函数? 好吧,每个派生对象都有一个子对象 - 这是父类的实际对象(我希望这句话不难理解)。
编译器将:
1)找到派生类的构造函数,其初始化程序列表最适合传递的参数,但不执行它;
2)执行基类的构造函数以创建子对象;
3)执行派生类的构造函数,以创建实际对象。
我希望这很清楚;你可以在上面的答案中找到更详细的解释:)