在C++中,不能声明虚构造函数,但是可以声明虚析构函数。
析构函数没有类型,也没有参数,和普通成员函数相比,虚析构函数情况很简单。
虚析构函数的声明语法:
virtual ~类名();
如果一个类的析构函数是虚函数,那么由该类派生而来的所有子类的析构函数也是虚函数。析构函数设置为虚函数之后,在使用指针引用时可以动态绑定,实现运行时的多态,保证使用基类类型的指针就能够调用适当的析构函数针对不同的对象进行清理工作。
如果有可能通过基类指针调用对象的析构函数,就需要让基类的析构函数成为虚函数,否则会产生不确定的后果。
【例】虚析构函数举例
class B
{
public:
~B();
};
B::~B()
{
cout << "基类的析构函数" << endl;
}
class D :public B
{
public:
D();
~D();
private:
int* p;
};
D::D()
{
p = new int(0);
cout <<"派生类D构造的对象:" << *p << endl;
}
D::~D()
{
cout << "派生类的析构函数" << endl;
delete p;
}
void fun(B* b)
{
delete b;
}
int main()
{
B* b = new D();//用基类指针b指向一个派生类D类型的动态内存单元
fun(b);
return 0;
}
运行结果:
分析:
由输出的结果可以说明,通过基类指针删除派生类对象时调用的是基类的析构函数,派生类的析构函数没有被执行,因此派生类对象中动态分配的内存空间没有得到释放,造成了内存泄漏。也就是说派生类对象成员p所指向的内存空间,在对象消失后既不能被本程序继续使用也没有被释放。对于内存需求量较大、长期连续运行的程序来说,如果持续发生这样的错误是非常危险的,最终导致因内存不足而引起程序终止。
通过派生类指针删除派生类对象时调用的仍然是基类的析构函数。
为了避免上述错误的有效方法是:把析构函数声明为虚函数:
class B
{
public:
virtual ~B();
};
B::~B()
{
cout << "基类的析构函数" << endl;
}
class D :public B
{
public:
D();
virtual ~D();
private:
int* p;
};
D::D()
{
p = new int(0);
cout <<"派生类D构造的对象:" << *p << endl;
}
D::~D()
{
cout << "派生类的析构函数" << endl;
delete p;
}
void fun(B* b)
{
delete b;
}
int main()
{
B* b = new D();//用基类指针b指向一个派生类D类型的动态内存单元
fun(b);
return 0;
}
运行结果:
分析:
这说明派生类的析构函数被调用了,派生类对象中动态申请的内存空间被正确的释放了。这是由于使用了虚析构函数,实现了多态。