析构函数
析构函数与构造函数对应,当对象结束其生命周期,系统会自动执行析构函数。它不能带任何参数,也没有返回值(包括void类型)。只能有一个析构函数,不能重载。
如果一个类中有指针,且在使用的过程中动态的申请了内存,那么最好显示构造析构函数在销毁类之前,释放掉申请的内存空间,避免内存泄漏。
析构函数的执行顺序:1)派生类本身的析构函数体;2)对象成员析构函数;3)基类析构函数。
虚析构函数
如果一个类的析构函数时虚函数,那么由它继承而来的所有子类的析构函数也是虚函数。析构函数被定义为虚函数之后,在使用指针引用时可以动态绑定,实现运行时的多态,保证使用基类指针就能够调用适当的虚构函数针对不同的对象进行清理工作。因此,对于有可能会被继承的父类的析构函数应设置为虚函数,我们使用基类指针指向该子类对象,释放基类指针时可以释放掉子类的空间,防止内存泄漏。
class A{
public:
~A(){
cout << "A destructor" << endl;
}
};
class B:public A{
public:
B(){
p = new int(0);
}
~B(){
cout << "B destructor" << endl;
delete p;
}
private:
int *p;
};
void fun(A *a){
delete a;
}
int main(){
A* b = new B();
fun(b);
return 0;
}
运行结果为:
A destructor
说明通过基类指针删除派生类对象时调用的是基类的析构函数,派生类的析构函数没有被执行,因此派生类对象中动态分配的内存没有得到释放,从而造成内存泄漏。
避免上述错误的有效方法是将析构函数声明为虚函数,实现多态:
class A{
public:
virtual ~A(){
cout << "A destructor" << endl;
}
};
此时输出信息为:
B destructor
A destructor
那么,为什么C++默认的析构函数不是虚函数?
C++默认的析构函数不是虚函数是因为虚函数需要额外的虚函数表和虚表指针,占用额外的内存。而对于不会被继承的类来说,其析构函数如果是虚函数,就会浪费内存。因此C++默认的析构函数不是虚函数,而是只有当需要当作父类时,设置为虚函数。