Bootstrap

C/C++基础 -- 析构函数

本博文由 西北工业大学MOOC 总结而来,以备以后回顾。(侵删)

1、析构函数

1.1、析构函数的定义

  当对象脱离其作用域时(例如对象所在的函数已调用完毕), 系统会自动执行析构函数。 析构函数往往用来做“清理善后”的工作(例如在建立对象时用new开辟了一段内存空间, 则在该对象消亡前应在析构函数中用delete释放这段存储空间)。
  C++规定析构函数的名字是类名的前面加一个波浪号(~) 。 其定义形式为

~ 类名()
{
	函数体
}

  析构函数不返回任何值, 没有返回类型, 也没有函数参数。 由于没有函数参数, 因此它不能被重载。 换言之, 一个类可以有多个构造函数, 但是只能有一个析构函数

1.2、何时调用析构函数

  1. 对象在程序运行超出其作用域时自动撤销, 撤销时自动调用该对象的析构函数。 如函数中的非静态局部对象。
  2. 如果用new运算动态地建立了一个对象, 那么用delete运算释放该对象时, 调用该对象的析构函数。

1.3、合成析构函数

  编译器总是会为类生成一个析构函数, 称为合成析构函数(synthesized destructor) 。

  合成析构函数按对象创建时的逆序撤销每个非静态成员, 即它是按成员在类中声明次序的逆序撤销成员的。 对于类类型的每个成员,合成析构函数调用该成员的析构函数来撤销对象。

  合成析构函数并不删除指针成员所指向的对象, 它需要程序员显式编写析构函数去处理。这就是为什么需要编写析构函数。

2、何时需要编写析构函数

  许多类不需要显式地编写析构函数, 尤其是具有构造函数的类不一定需要定义自己的析构函数。 析构函数通常用于释放在构造函数或在对象生命期内获取的资源(如动态分配的内存,构造指针型的类成员时,使用new为其分配内存空间,在析构时就要用delet释放其内存空间) 。
  同时,析构函数可以包含任意操作, 用来执行“对象即将被撤销之前程序员所期待的任何操作” ,如打印输出等。

*3、析构函数三法则

  如果类需要析构函数, 则该类几乎必然需要定义自己的复制构造函数赋值运算符重载, 这个规则称为析构函数三法则(rule ofthree) 。
  原因:
一、定义复制构造函数:
  当使用析构函数的时候,往往是因为类包含有指针类成员。当具有指针类成员,就应该注意深拷贝和浅拷贝的问题。如以下代码:

	Point pt1 = pt2;

  当Point类中具有指针类成员时,使用以上代码,使用 pt2 初始化 pt1,即将 pt2 中的内容复制给 pt1 。
  由于编译器默认使用浅拷贝,即将指针类成员的地址值进行拷贝,则 pt1 和 pt2 将指向同一块存储空间。在释放两个类成员指针的时候,会对同一块存储空间释放两次,而导致错误。所以,需要自定义复制构造函数,实现深拷贝
二、定义赋值运算符重载:
  当进行类的赋值运算时,也涉及指针类成员的深拷贝和浅拷贝问题。 如下所示:

	pt1 = pt2;

  当使用编译器默认的赋值运算符的功能,则依旧是简单的浅拷贝,只是将指针类成员指向的地址进行赋值。
  因此我们需要重载赋值运算符,实现类赋值的深拷贝。

*4、构造函数和析构函数的调用次序

  构造函数和析构函数的调用很像一个栈的先进后出, 调用析构函数的次序正好与调用构造函数的次序相反。 最先被调用的构造函数,其对应的(同一对象中的) 析构函数最后被调用, 而最后被调用的构造函数, 其对应的析构函数最先被调用。
  即:先构造的后析构, 后构造的先析构。在这里插入图片描述

5、实例:

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

;