上一次总结了点虚函数的一点原理和基础,也都是比较平常的函数,这次涉及到一点C++中重要的析构函数。
虚析构函数,在C++程序中,当基类中存在虚函数的时候,必然需要使得基类的指针对象指向其他派生类型的对象,当在结束的时候释放基类类型的指针会发生一些未定义的行为(没有析构派生类的对象,应该是内存泄漏),看一下代码:
#define CRTDBG_MAP_ALLOC
#include <iostream>
using namespace std;
class A
{
public:
int a = 1;
int b = 2;
virtual void f()
{
cout << "这是 A" << endl;
}
virtual ~A()
{
cout << "析构A" << endl;
}
};
class B :public A
{
public:
void f()
{
cout << "这是 B" << endl;
}
virtual ~B()
{
cout << "析构B" << endl;
}
};
int main()
{
B *b = new B();
A *a = b;
//A *a = new A(); //这种方式构造,再将b赋值给a肯定内存泄露,这是普通的内存管理问题
a = b;
a->f();
//delete b; //直接delete b即使类A没有虚析构函数也没问题,也照样会析构a和b
delete a; //如果基类没有虚析构函数,则只会析构a
_CrtDumpMemoryLeaks(); //这里用作动态内存分配的检测
system("pause");
return 0;
}
可以看出,释放指向派生类的基类类型指针时,不会析构派生类对象,但直接释放派生类指针则没事,这和普通的动态内存管理不同。
int *a = new int;
int *b = a;
delete b;
//这里会释放a申请的那段内存,与类中的不同。
回到虚析构函数,是因为基类的析构函数不是虚函数的话,不能发生动态绑定,那样自然也不能调用子类的析构函数,这是我听说过的原因。这也解释了,基类没有虚析构函数时,delete 基类类型指针的时候不会析构派生类的指针,当delete派生类的指针时都可以析构吧,也许就是这个原因。不过我就特别纳闷,基类能调用派生类析构函数(不管是不是虚的)?不能吧!这个说法还是不能让我信服。不过,当我们使用派生的时候,就添加一个虚析构函数,省得出什么妖蛾子。编译器不主动添加应该是为了效率和空间吧。
虚构造函数,是不允许有虚构造函数的,就像前面说的,vptr储存在对象中,是先有对象再有vptr,没有vptr就不会找到vtable中所谓的虚构造函数,所以不存在所谓的虚构造函数。对于编译器来说,也不会创建类型不明确的对象。