析构函数
我们知道,构造函数是用来在创建对象时初始化对象的,做一些赋初值等操作,那么相对的,析构函数是为了在结束对象的生命周期时做善后工作,比如在构造函数中申请的内存就需要在析构函数中释放(过程中根据情境已经做了特殊处理释放了内存的除外),构造和析构不需要主动调用,由系统自动调用,当类中没有析构函数时,系统会自动生成,类的析构函数主要是为了释放内存资源,析构函数如果不被调用的话就可能会造成内存泄漏。
虚析构函数
和虚函数一样,虚析构函数就是在析构函数之前加个virtual,为什么要这样做呢,先看一下下边这个例子:
#include <string>
#include <iostream>
using namespace std;
class Parent
{
public:
Parent() {}
~Parent() { cout << "~Parent()" << endl; }
};
class Child : public Parent
{
public:
Child() : Parent() {}
~Child() { cout << "~Child()" << endl; }
};
int main()
{
cout << "*********************" << endl;
Child* pChild = new Child();
cout << "delete pChild" << endl;
delete pChild;
cout << "*********************" << endl;
Parent* pParent = new Child();
cout << "delete pParent" << endl;
delete pParent;
cout << "*********************" << endl;
getchar();
return 0;
}
从输出中可以看出,当指针指向子类,delete时会先调用子类的析构函数,再调用父类的析构函数,而当指针指向父类,delete时只调用父类的析构函数,子类的析构函数不会被调用,如果子类的析构函数里有释放内存的操作,也同样不会执行,就造成了内存泄漏。而如果把父类的析构函数变为虚析构函数,又会怎么样呢,对上边的例子小小改动一下:
#include <string>
#include <iostream>
using namespace std;
class Parent
{
public:
Parent() {}
virtual ~Parent() { cout << "~Parent()" << endl; }
};
class Child : public Parent
{
public:
Child() : Parent() {}
~Child() { cout << "~Child()" << endl; }
};
int main()
{
cout << "*********************" << endl;
Child* pChild = new Child();
cout << "delete pChild" << endl;
delete pChild;
cout << "*********************" << endl;
Parent* pParent = new Child();
cout << "delete pParent" << endl;
delete pParent;
cout << "*********************" << endl;
getchar();
return 0;
}
这一次当指针指向父类,delete时先调用了子类的析构函数,再调用父类的析构函数,只是在父类的析构函数前多加了一个virtual结果就完全不同了。
通过上边的两小段代码,应该有所体会虚析构函数究竟要做什么了,虚析构函数是为了确保当指针指向基类时,删除能够彻底,但是也并不是所有类的析构函数都要写成虚析构函数的,只有当一个类作为基类使用,才需要把析构函数写成虚函数的形式。