从为什么要将基类的析构函数定义为虚函数谈起~~

 首先,做一个最简单的实验,在电脑上运行下面的代码,将会产生运行错误,这或许会使你百思不得其解:

#include <iostream>
using namespace std;

class Base
{
private:
    int a;
public:
    ~Base(){cout << "Base dtor..." << endl;}
};

class Derived : public Base
{
private:
    int b;
public:
     ~Derived(){cout << "Derived dtor..." << endl;}
};
int main()
{
    Base *b = new Base();
    Base *d = new Derived();
    delete b;
    delete d; //这一步出现了运行时错误
    return 0;
}
显然,这里出现了内存泄露。


记得刚开始学继承的时候,似乎就被强行的记住 “基类的析构函数要是虚函数!!”,可是为什么呢?

显然,这与对象在内存中的布局方式有关。


在C++中,如果类中有虚函数,那么它就会有一个虚函数表的指针__vfptr,在类对象最开始的内存数据中。之后是类中的成员变量的内存数据。


值得注意的是,无论继承(单层)层次有多深,对象中都只有一个虚函数指针。。

也就是说,如果Derived2 继承 Derived ,最终的内存布局中也只有一个虚函数指针。

那么上述类在内存中的存在方式如下图:

显然,这可以很好的解释 析构函数 是virtual的例子了,也就是说,如果析构函数不是virtual,那么在

Base *d = new Derived();该d对象所指向的是derived的虚函数表(因为虚函数表在对象内存的起始位置),这样便可以通过Base的指针找到derived对象的析构函数,从而在 delete  d ; 的时候可以释放Derived对象,不会导致内存泄露。


事实上,只需要将继承层次的最顶端的父类的析构函数设为虚函数,就可以避免上述问题,因为基类的析构函数是虚的,那么它的子类的析构函数也是虚的。


拓展:如果在基类中还存在其他的虚函数,很简单,直接将该虚函数存放在虚函数列表中,如果子类继承了改虚函数,那么只需要将子类对象的虚函数表中的函数替换为子类定义的版本即可。没有继承的,则沿用父类的版本。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值