Effective C++条款07:为多态基类声明virtual析构函数

本文深入探讨了在C++中,基类为何需要声明虚析构函数,特别是在涉及多态和派生类的情况下。通过代码示例,展示了当基类没有虚析构函数时,派生类资源无法正确释放,导致内存泄漏的问题。强调了虚析构函数对于资源管理的必要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

显而易见,这个条款和多态的这个特性息息相关。多态的其中一个重要是通过我们在基类中的声明虚函数,子类进行重写(override)。那么在基类中,我们声明了虚函数或者纯虚函数,那么我们应该对应地就要有虚析构函数,但是往往我们会忽略这个问题,这就会导致严重的内存泄漏问题。

下面我们上代码:

class base  //这里的基类并没有声明虚析构函数
{
	public:
		base()
		{
			std::cout<<"creating base class!"<<std::endl;
		}
		virtual test()
		{
			std::cout<<"test for base class"<<std::endl;
		}
		
		~base()
		{
			std::cout<<"destrying base class!"<<std::endl;
		 } 
 };
 
class derived:public base  //继承基类的子类
 {
 	public:
 		derived()
		{
		 	std::cout<<	"creating derived class!"<<std::endl;
		}
		test()
		{
			std::cout<<"test for derived base class"<<std::endl;
		}
		~derived()
		{
			std::cout<<"destrying derived class!"<<std::endl;
		 } 
 };
 int main()
 {
 	base *a = new derived();
 	a->test();
 	delete a;
 	return 0;
  } 

我们可以看到这里是声明一个父类指针指向了建立的子类对象。我们看一下运行结果:

我们可以看到,这里的析构函数只调用了基类的析构函数,这说明,派生类中的成分并没有被析构,这就会造成资源、内存的泄漏。

但我们将基类的析构函数改为虚析构函数:


class base
{
	public:
		base()
		{
			std::cout<<"creating base class!"<<std::endl;
		}
		virtual test()
		{
			std::cout<<"test for base class"<<std::endl;
		}
		
		virtual ~base()
		{
			std::cout<<"destrying base class!"<<std::endl;
		 } 
 };

我们可以看到结果如下:

显而易见,此时,析构时,基类和派生类的析构函数都被调用,程序按照我们的预期结束。

之所以会这样的原因如下:

原因是基类指针指向了派生类对象,而基类中的析构函数却是非virtual的,我们都知道,虚函数是动态绑定的基础。现在析构函数不是virtual的,因此不会发生动态绑定,而是静态绑定,指针的静态类型为基类指针,因此在delete时候只会调用基类的析构函数,而不会调用派生类的析构函数。这样,在派生类中申请的资源就不会得到释放,就会造成内存泄漏,这是相当危险的:如果系统中有大量的派生类对象被这样创建和销毁,就会有内存不断的泄漏,久而久之,系统就会因为缺少内存而崩溃。

 

需要记住的点:

1、polymorphic(带多态性质的)base class应该声明一个virtual析构函数。如果class带有任何virtual函数,他就应该拥有一个virtual析构函数。

2、classes的设计目的如果不是作为base classes使用,或者不是为了具备多态性质,就不应该声明virtual析构函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值