如何在C ++中实现构造函数和析构函数?

时间:2010-09-01 11:23:13

标签: c++ implementation

我有2个类Base和Derived(从Base公开派生)。 当我写 -

Derived * d1 = new Derived;
delete d1;

编译器发现d1是派生类型对象。所以它调用派生类构造函数(调用基类构造函数)。我在这里有2个问题 -

1)为什么我们遵循这个命令?

2)这些构造函数如何协同工作来分配内存?我需要一些实现细节

现在下一个语句是删除d1。因此编译器看到d1是派生类型对象,因此调用派生类的destuctor(在删除派生类成员后调用基类的析构函数)。我在这里有一个问题 -

1)这些析构函数如何协同工作?让我们说派生类析构函数在内存中传递d1的地址。这些析构函数现在如何释放空间?

6 个答案:

答案 0 :(得分:2)

该代码无法编译。您不能delete自动实例,必须使用new分配实例才能在其上使用delete

当谈到构造函数的顺序时,我想运行它们是有意义的,这样更专业的类可以依赖于已经完成的更一般的部分。

编译器知道每个类的内存布局,检查完整的类声明并通过任何和所有超类递归。

答案 1 :(得分:2)

1)默认情况下,自动调用基类构造函数。但是,允许派生的构造函数在其初始化列表中显式调用基类构造函数 。如果构造函数没有执行派生类优先,那么这是不可能的。

Derived::Derived() : foo( 42 ), bar( 7 ), Base( 1, 2 ) { }

2)编译器知道派生类的内存占用(因为所有成员变量在编译时都是已知的),并分配足够的内存来保存基类和派生类成员。有关内存布局的详细信息由系统使用的ABI指定。

3)析构函数不只是释放内存。实际上,析构函数释放保存任何成员变量所需的内存 - 仅在必要时,成员指针指向的内存。

答案 2 :(得分:1)

您提供的代码示例无法编译。 delete适用于指针,而不是对象。

我不认为C ++本身(语言标准)说明了如何使用内存来表示使用继承的类型的实例。但是,在大多数实现中,从免费存储分配单个内存块,其大小足以容纳BaseDerived的所有数据。删除Derived的实例时,两个构造函数都会运行,然后释放单个内存块。

同样,如果Derived的实例是某个类Container的嵌入数据成员,那么保存Container实例的内存块将足够大以容纳Derived {1}}(以及Base)和Container的所有其他数据。

答案 3 :(得分:1)

(1)基类不依赖于派生类,但可以采用其他方法。即Base班级无法知道任何Derived班级有哪些字段,因此Base::Base不会也无法触及它们。另一种方法是,Derived::Derived可以访问Base::member。因此,Base::memberBase::Base Base :: member`之前由Derived::Derived gets the chance to use初始化。

(2)构造函数不分配内存。这是new的任务。或者如果对象是全局的,编译器的。调用构造函数,this已指向已分配的内存;它只需要填写该位置的成员。

对于base和派生构造函数,一个常见的实现在Derived构造函数的生成代码中插入对Base构造函数的调用。对于单继承,Base和Derived类通常共享相同的this指针,因此Derived constrcutor可以传递它获得的相同指针。

(1) [sic]就像构造函数不分配内存一样,析构函数也不会释放它。这是delete的任务 - 再次,对于全局变量,编译器会这样做。

答案 4 :(得分:0)

构造时,构造函数从最高基类调用,直到派生最多的构造函数,这将被称为最新的。

当调用析构函数时,它是相反的顺序。首先称为最大派生的destuctor,直到最高基类之一。

答案 5 :(得分:0)

在继承中,编译器应该知道它继承了什么。它应该知道Base类包含什么。它不能从一个类继承,它没有任何想法。 因此,首先调用Base类构造函数然后调用Derived确实有意义。

在Destruction的情况下,如果首先调用Base析构函数并被破坏,Derived类可能仍在使用无效的Base类成员。因此,Destruction是结构的确切反转..

相关问题