继承的类数据成员
Inherited class data members
我有点困惑,我正在阅读这个C++构造函数/析构函数继承,所以它说构造函数和析构函数不是从基类继承到派生类的,而是在我创建派生对象时调用构造函数和析构函数。那么基类的构造函数和析构函数是继承类的数据成员吗?
构造函数和析构函数是非常特殊的动物;事实上,该标准将它们确定为"特殊成员职能"
构造函数和析构函数的所有奇怪和独特之处(例如,它们没有"名称",也没有"继承")实际上与几乎所有编程和程序员都无关。以下是您需要了解的内容:
构造函数和析构函数(显然)不是成员变量——它们是(特殊的)成员函数。
从基类派生时,将调用基类的一些构造函数哪个构造函数取决于您编写代码的方式。如果没有明确指定要调用的构造函数,则将调用默认构造函数。这种情况发生在派生对象的初始化列表中,即使您还没有编写初始化列表。
您可以通过初始化列表指定另一个构造函数,仅限:
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
的构造函数主体启动之前,所有的Bar
基类和成员变量都已实例化和初始化。这就是为什么除了默认构造函数之外,为Foo
指定某些构造函数的唯一方法是通过初始化列表——这也是为什么如果基类没有可用的默认构造函数,则必须具有初始化列表的原因。
问题:如果构造函数和析构函数不是继承的,那么为什么在实例化派生类型时调用它们?
答:因为构造函数是初始化对象的对象,并且派生类型与基类型有IS-a关系。
再次考虑上面的Foo
和Bar
。Bar
来源于Foo
,因此在某种意义上Bar
ISBar
。它不仅仅是一个Foo
,它有Foo
没有的东西;但它具有所有的CCD_ 15性质。由于Bar
对象在一定程度上是Foo
,因此必须初始化该Foo
。由于所有ob对象的初始化都是通过构造函数完成的,因此必须调用Foo
的构造函数。
因此,构造函数和析构函数不是从重载的意义上继承的,而是基类的构造函数将被调用。它们必须是。否则,Bar
对象的Foo
性质永远不会成为。
当您从基类派生时,您通常想要做的事情是传递一个指向基类的指针。事实上,在许多情况下,您可能根本不需要指向派生类型的指针。在设计抽象接口时尤其如此。
当你这样做并且没有做好所有必要的准备时,会出现一个令人讨厌的问题。考虑:
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
析构函数没有被调用——留下了65K长的庞大数组。
为了解决这个问题,我们需要给Foo
一个virtual
析构函数:
class Foo
{
public:
std::string mS;
virtual ~Foo() {}
};
这并没有多大作用,但它做了一件关键的事情:它设置了多态性,这样当我们(隐式)调用析构函数时,就会调用虚拟覆盖。
这是设计类层次结构的关键步骤。如果你认为人们有可能传递指向基类的指针,那么你应该在基类中有一个virtual
析构函数。事实上,我建议在几乎所有情况下都应该有一个virtual
析构函数,即使你不认为人们会这样使用它。
否。正如您所说,构造函数和析构函数都不是继承的(顺便说一句,赋值运算符也不是)。如果他们被继承,在逻辑上是有缺陷的,对吧?构造函数(和析构函数)是特定于该类的;由于派生类通常有一些特定的和新的东西,基构造函数不足以初始化继承的类对象。
那么,为什么在创建子类的对象时调用基构造函数呢?每个派生对象都有一个子对象,这是父类的实际对象(我希望这句话不难理解)。
编译器将:
1) 查找派生类的构造函数,该派生类的初始值设定项列表最适合传递的参数,但不执行它;
2) 执行基类的构造函数以创建子对象;
3) 执行派生类的构造函数,以创建实际对象。
我希望这是清楚的;您可以在上面的答案中找到更详细的解释:)
- 派生类不从基类继承数据成员
- 虚拟继承的性能开销(如果只有一个基具有数据成员)
- C 继承访问受保护的数据成员
- 继承的类对象如何使用私有数据成员
- 子类是否也在 c++ 中继承私有数据成员?但通过超类的公共方法访问
- 结构绑定:与公共数据成员(继承的基类)结合
- 基础和派生类C 之间的继承数据成员
- 指向具有继承类型的类数据成员的指针
- 继承的类数据成员
- 模板类和继承问题 - 'List'不命名非静态数据成员或基类
- 指向多重继承中继承的数据成员的指针
- 当基类不包含数据成员时,虚拟继承是否仍然是必要的
- 在实现中,继承是来自连续分配的多个层的数据成员
- 在继承的情况下,每个类的静态数据成员是唯一的
- 继承的静态函数能否访问重写的静态专用数据成员
- 派生类构造函数初始化列表中的多重继承和继承的数据成员
- 访问数据成员的继承成员函数
- C++类继承设置"classA"数据成员等于"ClassB"
- 数据成员访问歧义和菱形继承
- 是否可以将友谊与继承结合起来访问私有数据成员?