1 对象的销毁
- 生活中的对象都是被初始化后才上市的。
- 生活中的对象被销毁前会做一些清理工作。
问题:C++ 中如何清理需要销毁的对象?
- 一般而言,需要销毁的对象都应该做清理。
- 解决方案:
- 为每一个类提供一个public的free函数;
- 对象不再需要时立即调用free函数进行清理。
- 存在的问题:
- free只是一个普通的函数,必须显示的调用;
- 对象销毁前没有做清理,很可能造成资源泄漏。
C++ 编译器是否能够自动调用某个特殊的函数进行对象的清理?
2 析构函数
C++的类中可以定义一个特殊的清理函数:
- 这个特殊的清理函数叫做析构函数;
- 析构函数的功能和构造函数相反。
定义:~ClassName()
- 析构函数没有参数也没有返回值类型声明;
- 析构函数在对象销毁时自动被调用。
编程实验:析构函数使用初探
#include <stdio.h>
class Test
{
int mi;
public:
Test(int i)
{
mi = i;
printf("Test(): %d\n", mi);
}
~Test()
{
printf("~Test(): %d\n", mi);
}
};
int main()
{
Test t(1);
Test* pt = new Test(2);
delete pt; //这里会调用析构函数,如果不delete则不会调用析构函数
return 0; //在return之前会销毁对象t
}
析构函数的定义准则
当类中自定义了构造函数,并且构造函数中使用了系统资源(如:内存申请、文件打开等),则需要自定义析构函数。
小结
- 析构函数是对象销毁时进行清理的特殊函数。
- 析构函数在对象销毁时自动被调用。
- 析构函数是对象释放系统资源的保障。
3 析构的顺序
关于析构的疑问:当程序中存在多个对象的时候,如何确定这些对象的析构顺序?
- 单个对象创建时构造函数的调用顺序:
- 调用父类的构造过程。
- 调用成员变量的构造函数(调用顺序与声明顺序相同)。
- 调用类自身的构造函数。
单个对象析构函数与对应构造函数的调用顺序相反。
- 多个对象析构时
- 析构顺序与构造顺序相反。
实例分析:构造与析构顺序
#include <stdio.h>
class Member
{
const char* ms;
public:
Member(const char* s)
{
printf("Member(const char* s): %s\n", s);
ms = s;
}
~Member()
{
printf("~Member(): %s\n", ms);
}
};
class Test
{
Member mA;
Member mB;
public:
Test() : mB("mB"), mA("mA")
{
printf("Test()\n");
}
~Test()
{
printf("~Test()\n");
}
};
Member gA("gA");
int main()
{
Test t;
return 0;
}
/*
Member(const char* s): gA
Member(const char* s): mA
Member(const char* s): mB
Test()
~Test()
~Member(): mB
~Member(): mA
~Member(): gA
*/
关于析构的答案
- 对于栈对象和全局对象,类似于栈与出栈的顺序,最后构造的对象最先被析构!!
- 堆对象的析构发生在使用delete的时候,与delete的使用顺序相关!!