C++析构函数的定义和使用
创建对象时,系统会为对象分配所需要的内存空间等资源,当程序结束或对象被释放时,系统为对象分配的资源也需要回收,以便可以重新分配给其他对象使用。
在 C++ 中,对象资源的释放通过析构函数完成。
析构函数的作用是在对象被释放之前完成一些清理工作。析构函数调用完成之后,对象占用的资源也被释放。
与构造函数一样,析构函数也是类的一个特殊成员函数,其定义格式如下所示:
析构函数的调用情况主要有以下几种:
注意:析构函数的调用顺序与构造函数的调用顺序是相反的。在构造对象和析构对象时,C++ 遵循的原则是:先构造的后析构,后构造的先析构。
例如,连续创建了两个对象 A1 和 A2,在创建时,先调用构造函数构造对象 A1,再调用构造函数构造对象 A2;
在析构时,先调用析构函数析构对象 A2,再调用析构函数析构对象 A1。
在创建对象的过程中,对象 A 与对象 B 除了对象本身所占用的内存空间,还各自拥有一块 new 运算符在堆上申请的空间,对象 A 与对象 B 占用的内存空间如图 1 所示。

图1 对象A与对象B占用的内存空间
程序运行结束后,编译器会调用析构函数释放对象资源,在释放时,先释放 _food 指向的内存空间,再释放对象所占用的内存空间。
由运行结果可知,程序成功调用了析构函数,并且析构的顺序是先析构对象 B,再析构对象 A。
声明:《C++系列教程》为本站“54笨鸟”官方原创,由国家机构和地方版权局所签发的权威证书所保护。
在 C++ 中,对象资源的释放通过析构函数完成。
析构函数的作用是在对象被释放之前完成一些清理工作。析构函数调用完成之后,对象占用的资源也被释放。
与构造函数一样,析构函数也是类的一个特殊成员函数,其定义格式如下所示:
class 类名
{
~析构函数名称();
... //其他成员
}
-
析构函数的名称与类名相同,在析构函数名称前添加
~
符号。 - 析构函数没有参数。因为没有参数,所以析构函数不能重载,一个类中只有一个析构函数。
- 析构函数没有返回值,不能在析构函数名称前添加任何返回值类型。在析构函数内部,也不能通过 return 返回任何值。
- 当程序结束时,编译器会自动调用析构函数完成对象的清理工作,如果类中没有定义析构函数,编译器会提供一个默认的析构函数,但默认的析构函数只能完成栈内存对象的资源清理,无法完成堆内存对象的资源清理。因此,在程序中往往需要自定义析构函数。
析构函数的调用情况主要有以下几种:
- 在一个函数中定义了一个对象,当函数调用结束时,对象应当被释放,对象释放之前编译器会调用析构函数释放资源。
- 对于static修饰的对象和全局对象,只有在程序结束时编译器才会调用析构函数。
- 对于new运算符创建的对象,在调用delete释放时,编译器会调用析构函数释放资源。
注意:析构函数的调用顺序与构造函数的调用顺序是相反的。在构造对象和析构对象时,C++ 遵循的原则是:先构造的后析构,后构造的先析构。
例如,连续创建了两个对象 A1 和 A2,在创建时,先调用构造函数构造对象 A1,再调用构造函数构造对象 A2;
在析构时,先调用析构函数析构对象 A2,再调用析构函数析构对象 A1。
示例
下面通过案例演示析构函数的定义与调用,C++ 代码如下:#define _CRT_SECURE_NO_WARNINGS #include<iostream> using namespace std; class Rabbit //定义兔子类Rabbit { public: Rabbit(string name,const char* pf); //声明构造函数 void eat(); ~Rabbit(); //声明析构函数 private: string _name; //声明表示兔子名字的成员变量 char* _food; //声明表示兔子食物的成员变量 }; Rabbit::Rabbit(string name, const char* pf) { cout<<"调用构造函数"<<endl; _name=name; _food=new char[50]; //为_food指针申请空间 memset(_food,0,50); //初始化_food空间 strcpy(_food,pf); //将参数pf指向的数据复制到_food中 } void Rabbit::eat() { //类外实现成员函数 cout<<_name<<" is eating "<<_food<<endl; } Rabbit::~Rabbit() //类外实现析构函数 { cout<<"调用析构函数,析构"<<_name<<endl; if(_food != NULL) delete []_food; } int main() { Rabbit A("A","luobo"); A.eat(); Rabbit B("B","baicai"); B.eat(); return 0; }运行结果:
调用构造函数
A is eating luobo
调用构造函数
B is eating baicai
调用析构函数,析构B
调用析构函数,析构A
- 第 4~13 行代码,定义了一个兔子类 Rabbit,该类有两个成员变量,分别是 _name、_food,有一个构造函数、一个析构函数和一个普通成员函数 eat();
- 第 14~21 行代码在类外实现构造函数。在实现构造函数时,由于第二个成员变量 _food 是字符指针变量,因此在赋值时,要先使用 new 运算符为 _food 指针申请一块内存空间并初始化,再将参数 pf 指向的数据复制到 _food 指向的空间;
- 第 22~25 行代码在类外实现 eat() 函数;
- 第 26~31 行代码在类外实现析构函数,在析构函数中,使用 delete 运算符释放 _food 指向的内存空间;
- 第 34~37 行代码,在 main() 函数中,分别创建两个对象 A 和 B,然后调用成员函数 eat() 实现吃食物的功能。
在创建对象的过程中,对象 A 与对象 B 除了对象本身所占用的内存空间,还各自拥有一块 new 运算符在堆上申请的空间,对象 A 与对象 B 占用的内存空间如图 1 所示。

图1 对象A与对象B占用的内存空间
程序运行结束后,编译器会调用析构函数释放对象资源,在释放时,先释放 _food 指向的内存空间,再释放对象所占用的内存空间。
由运行结果可知,程序成功调用了析构函数,并且析构的顺序是先析构对象 B,再析构对象 A。
声明:《C++系列教程》为本站“54笨鸟”官方原创,由国家机构和地方版权局所签发的权威证书所保护。