一 概念
通过前面构造函数的学习,我们知道一个对象是怎么来的,那一个对象又是怎么没呢的?
析构函数:与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作(Destroy).
二 特性
析构函数是特殊的成员函数,其特征如下:
1. 析构函数名是在类名前加上字符 ~。
class A
{
public:
A(int value)//构造函数
{
i = value;
}
~A()//析构函数
{
}
private:
int i;
};
2. 无参数无返回值类型。
3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构
函数不能重载
class C
{
public:
~C() { }
~C(int i) { } // error C2524: “C”: 析构函数 必须有“void”参数列表
// warning C4523: “C”: 指定了多个析构函数
};
4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。
析构函数的作用并不是删除对象,而是在撤销对象占用的内存之前完成一些清理工作。
内置成员不做处理
自定义成员自动调用它的析构函数
class Stack
{
public:
Stack(size_t capacity = 3)
{
cout << "Stack(size_t capacity = 3)" << endl;
_a = (int*)malloc(sizeof(int) * capacity);
if (nullptr == _a)
{
perror("malloc申请空间失败!!!");
}
_capacity = capacity;
_top = 0;
}
~Stack()//析构函数
{
cout << "~Stack()" << endl;
free(_a);
_capacity = _top = 0;
_a = nullptr;
}
private:
int* _a;
int _capacity;
int _top;
};
class MyQueue
{
// 默认生成析构函数,行为跟构造类似
// 内置类型成员不做处理
// 自定义类型成员会去调用他的析构
private:
Stack _pushst;
Stack _popst;
int _size = 1;
};
int main()
{
//Stack st1;
MyQueue mq;
return 0;
}
如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,比如 Date类;有资源申请时,一定要写,否则会造成资源泄漏,比如Stack类。
5 构造顺序是按照语句的顺序进行构造,析构是按照构造的相反顺序进行析构
构造函数用于对对象中的变量赋初值,析构函数用于释放所定义的对象的所有内存空间。构造函数和析构函数都不需要用户调用的,构造函数在定义对象时自动调用,析构函数当对象的生存期结束的时候会自动的调用。一般来说,析构函数的调用顺序与构造函数相反。但对象存储类型可以改变析构函数的调用顺序。
全局范围中定义的对象的构造函数在文件中的任何其他函数(包括main)执行之前调用(但不同文件之间全局对象构造函数的执行顺序是不确定的)。全局变量是需要在进入main()函数前即初始化的,所以在一个程序中一个全局变量的构造函数应该是第一个被调用的,比main()函数都要早。同时全局对象又必须在main()函数返回后才被销毁,当main终止或调用exit函数时调用相应的析构函数,所以它的析构函数是最后才被调用。
当程序执行到对象定义时,调用自动局部对象的构造函数。该对象的析构函数在对象离开范围时调用(即离开定义对象的块时)。自动对象的构造函数与析构函数在每次对象进人和离开范围时调用。
static局部对象的构造函数只在程序执行首次到达对象定义时调用一次,对应的析构函数在main终止或调用exit函数时调用。
class A
{
public:
A(int value)
{
i = value;
cout << "Object " << i << " constructor";
}
~A() // destructor
{
cout << "Object " << i << " destructor" << endl;
}
private:
int i;
};
A first(1); // global object全局变量
void func()
{
A fifth(5);
cout << " (local automatic in create)" << endl;
static A sixth(6);
cout << " (local static in create)" << endl;
A seventh(7);
cout << " (local automatic in create)" << endl;
}
int main()
{
cout << " (global created before main)" << endl;
A second(2);
cout << " (local automatic in main)" << endl;
static A third(3); // local object
cout << " (local static in main)" << endl;
func(); // call function to create objects
A fourth(4); // local object
cout << " (local automatic in main)" << endl;
return 0;
}
下面总结下不同存储类型构造函数和析构函数的调用。
构造函数的调用:
(1)全局变量:程序运行前;
(2)函数中静态变量:函数开始前;
(3)函数参数:函数开始前;
(4)函数返回值:函数返回前;
析构函数的调用:
(1)全局变量:程序结束前;
(2)main中变量:main结束前;
(3)函数中静态变量:程序结束前;
(4)函数参数:函数结束前;
(5)函数中变量:函数结束前;
(6)函数返回值:函数返回值被使用后;
对于相同作用域和存储类别的对象,调用析构函数的次序正好与调用构造函数的次序相反
本节内容相对简单, 但是和构造函数有一定联系, 对构造函数基础不太好的可以去我博客【C++】类和对象(2)--构造函数-CSDN博客
【C++】类和对象(3)--初始化列表(再谈构造函数)-CSDN博客
继续加油!