理解虚析构函数

示例代码(普通析构)

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

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(基类的指针)调用析构函数的时候,必须发生动态绑定;
否则会导致派生类的析构函数无法调用。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值