为什么需要将继承层次中类的析构函数定义成virtual的?

  如标题所示,如果该类没有父类也没有任何子类,把析构函数还定义成虚的,确实没多大必要吧。对象的构建和析构完全是一个入栈和出栈的过程,也就是说肯定会从父类构造到子类,也肯定会从子类析构到父类,这些都是毋容置疑的。

  那么把析构函数定义成virtual有个什么意义了。确实没有多大意义,至少对于一个非delete造成的析构。无论是析构一个堆栈对象还是全局对象,编译器肯定能在编译时就做出决策了。但是,假如有人一时兴起,new了一个子类对象并且将地址存储在基类指针中。那么,你该怎么删除这个对象了,只能delete父类指针了。

  问题就出在这里了。你既然delete父类指针,假如是在编译层次决策的话,编译器只能帮你调用父类的析构函数了。但是,事实上你是一个子类对象,那么子类的析构函数没有调用,假如你在子类的析构函数做了些什么释放,结果就是那个释放永远不会执行,这样就造成内存泄漏或者资源重复申请之类的。

  其实,上面的这种写法就是利用多态的性质,既然要利用多态,肯定得把析构函数定义成virtual的,那么调用哪个析构函数的决策就能到运行时候再决定。如果基类的析构函数定义成virtual的话,其所有子类的析构函数当然也是virtual的,那么我们删除基类指针的时候,就能通过多态机制决定该调用子类的析构函数,也就是从子类的析构函数开始往基类的析构函数调用释放整个对象。这样就不会造成任何资源泄漏了。

  以下的代码展示了这样的一种情况,注意Class CA作为基类,就需要把析构函数定义成virtual的。

#include <stdio.h>

class CA
{
    public:
        CA(int nS = 100): nSize(nS)
        {
            nA = new int[nSize];
            printf("构造CA\n");
        }
        virtual ~CA()
        {
            delete [] nA;
            printf("析构CA\n");
        }

    private:
        int* nA;
        int nSize;
};

class CB : public CA
{
    public:
        CB(int nS = 100): nSize(nS)
        {
            nB = new int[nSize];
            printf("构造CB\n");
        }
        ~CB()
        {
            delete [] nB;
            printf("析构CB\n");
        }

    private:
        int* nB;
        int nSize;
};

int main()
{
    CA* pCA = new CB();
    delete pCA;
}

效果如图:

  如果删掉CA析构函数前面的virtual,效果如图,

  你也可以实验在主函数里面定义些栈变量的CA和CB的对象,无论构造函数是否是virtual的,都能够正确的析构。

http://www.xpc-yx.com/2012/11/10/%e4%b8%ba%e4%bb%80%e4%b9%88%e9%9c%80%e8%a6%81%e5%b0%86%e7%bb%a7%e6%89%bf%e5%b1%82%e6%ac%a1%e4%b8%ad%e7%b1%bb%e7%9a%84%e6%9e%90%e6%9e%84%e5%87%bd%e6%95%b0%e5%ae%9a%e4%b9%89%e6%88%90virtual%e7%9a%84/
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值