虚析构函数

声明:本人学习c++不过月余许,按照c++primer第五版一点一点的啃,以下对虚析构函数的理解源于此书第十五章15.7.1节,或许会有理解错误的地方~,本文只是记录当前自己对虚析构函数的理解。


1.虚析构函数的定义,就是在析构函数前加virtual关键字。

2.何时需要需要析构函数?当一个类希望被子类继承的时候,就应该显示的定义之。

3.为什么希望被子类继承的时候,就应该显示的定义之?

为了理解这个这个问题,需要知道三个方面的知识:

1).delete的执行过程(此处专门指delete 对象指针),它有两个任务,第一,调用调用对象指针所指向的对象的析构函数。第二,释放指针指向的空间,标记其为空闲。

2).众所周知,在继承体系结构中,父类的指针或引用可以绑定子类的对象,那么此时,我们delete一个父类指针时其调用的析构函数应该是子类的析构函数,因为我们申请空间时是通过“new 子类”这种形式的。eg.有两个类base,son,base表基类,son表子类继承自base,我们先忽略其各自定义,看下面的语句

son *s=new son();
base *b=s;//静态类型和动态类型不一致
delete b;//delete时调用的析构函数我们希望应该要是son类的析构函数,但只是我们希望要如此而已。

3).编译器在执行过程是如何进行名字查找的呢?其实编译器是根据对象的静态类型进行查找的。也就是说,delete b时,会去查找base类的析构函数。


那么从上面三点可知,如果我们像以往那样不对基类的析构函数进行特殊处理,那么上例中delete b将会调用base类对象的析构函数,而非son类的析构函数。此时如果我们的son类中有成员指向堆中数据,将会造成内存泄露。


基于此,c++继承机制中引入了虚函数技术。可以让我们运行的函数能进行动态绑定。那么要解决上面的问题,只需要将基类base的析构函数定义成虚函数即可。子类继承父类的时候将会继承父类的虚属性,也就是说不管我们是否在子类中自定义了自己的析构函数,子类的析构函数都是虚函数。那么在执行delete b时,会去动态绑定需要调用的析构函数。

下面还有个两个小例子:

1.先不定义A类析构函数

#include <iostream>
using namespace std;

class base{
public:
	base(int *ptr=new int):p(ptr){}
	virtual ~base(){
		if(p)delete p;
	    cout<<"base destructor"<<endl;
	}
 
private: int *p;
};

class A :public base{
public:
	//~A(){cout<<"A destrucotr"<<endl;}
private: base b_obj;
};

int main()
{
	A *a=new A();
	base *ptrb=a;
	delete ptrb;
	system("pause");
}

结果:

第一个base destructor是释放A类的私有成员b_obj造成的。

第二个是调用父类析构函数造成的。

对这个结果理解需要明白析构函数的执行原理和步骤,这里不累赘

2.定义自己的虚析构函数

class A :public base{
public:
	~A(){cout<<"A destrucotr"<<endl;}//此处继承了父类的虚属性,无需显示加virtual
private:
	base b;
};

结果:

虚析构函数_第1张图片

这两个小例子说明了虚析构函数的目的。


注:要理解这些东西需要理解的知识点:

1.析构函数的目的,执行步骤

2.静态类型,动态类型

3.动态绑定

4.编译器如何查找需要调用的函数。



你可能感兴趣的:(C++,虚析构函数)