理解虚析构函数

Posted Redamanc

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了理解虚析构函数相关的知识,希望对你有一定的参考价值。

虚析构函数

示例代码(普通析构)

老样子,我们先来看如下代码:

class Base

public:
	Base(int data) :ma(data)  cout << "Base()" << endl; 
	~Base()  cout << "~Base()" << endl; 
	void show()  cout << "call Base::show()" << endl; 
private:
	int ma;
;

class Derive :public Base

public:
	Derive(int data) 
		:Base(data), mb(data)
	
		cout << "Derive()" << endl;
	
	~Derive()
	
		cout << "~Derive()" << endl;
	
private:
	int mb;
;

int main()

	Base* pb = new Derive(10);
	pb->show(); 
	delete pb; 
	
	return 0;

存在问题

我们先来看运行结果:

发现问题了吗?
缺少了~Derive()!也就是说,派生类的析构函数根本没有被执行!
这样一来,就会存在内存泄漏的问题。

原因分析

那么为什么不会调用派生类的析构函数呢?
原因就在于我们是用基类的指针,指向了上new出来的派生类对象
并且,基类的析构函数是普通函数,在函数调用的过程中,发生了静态绑定
也就是说,在编译时期,编译器就确定了调用析构函数的地址只有基类的析构函数;
派生类的析构函数没有机会得到执行。

修改代码(虚析构)

分析完原因之后,我们知道,调用析构函数的时候,必须发生动态绑定,否则会导致派生类的析构函数无法调用,故,修改代码如下:

class Base

public:
	Base(int data) :ma(data)  cout << "Base()" << endl; 
	virtual ~Base()  cout << "~Base()" << endl; 
	virtual void show()  cout << "call Base::show()" << endl; 
private:
	int ma;
;

class Derive :public Base

public:
	Derive(int data) 
		:Base(data), mb(data)
	
		cout << "Derive()" << endl;
	
	~Derive()
	
		cout << "~Derive()" << endl;
	
private:
	int mb;
;

int main()

	Base* pb = new Derive(10);
	pb->show(); 
	delete pb; 
	
	return 0;

这个时候我们再次运行程序:

这样一来,就能正确的析构派生类对象了。

相关问题

当然,关于虚析构函数还有很多相关的问题:

构造函数可以是虚函数吗?

要回答这个问题,我们需要了解虚函数依赖什么?
首先,虚函数能够产生地址,存储在vftable中,
其次,虚函数必须依赖对象,换句话说,对象必须存在
因为只有对象存在,通过对象的虚函数指针vfptr,访问到只读数据区vftable,这样才能得到虚函数的地址。
分析到这里,我们可以得出结论:构造函数不可以是虚函数
因为构造函数调用的时候,还没有对象

什么时候需要虚析构函数?

当基类的指针(引用)指向堆上new出来的派生类对象的时候
delete pb(基类的指针)调用析构函数的时候,必须发生动态绑定;
否则会导致派生类的析构函数无法调用。

以上是关于理解虚析构函数的主要内容,如果未能解决你的问题,请参考以下文章

C++虚函数表与虚析构函数

为啥我们需要 C++ 中的纯虚析构函数?

虚析构函数

虚析构函数详解

没有虚析构函数的类是危险的

虚析构函数,派生类调用基类构造方法