zoukankan      html  css  js  c++  java
  • 父类的析构函数设成虚的原因

    转自:https://blog.csdn.net/jacqueslim/article/details/6792105

    1. 一般来说,如果一个类要被另外一个类继承,而且用其指针指向其子类对象时,如题目中的A* d = new B();(假定A是基类,B是从A继承而来的派生类),那么其(A类)析构函数必须是虚的,否则在delete d时,B类的析构函数将不会被调用,因而会产生内存泄漏和异常;

    2. 在构造一个类的对象时,先构造其基类子对象,即调用其基类的构造函数,然后调用本类的构造函数;销毁对象时,先调用本类的析构函数,然后再调用其基类的构造函数;

    3. 题目给出的代码是可以编译的,但会出现运行时错误。错误出现在delete d;这一句。为讨论方便,我们不妨将A类和B类改写如下:

    class A
    {
    public:
        int a;
        ~A()
        {
            cout << "A::~A" << endl;
        }
    };

    class B : public A
    {
    public:
        int b;
        virtual ~B()
        {
            cout << "B::~B" << endl;
        }
    };
    那么A* d = new B();这一句的左边所产生B的对象的内存结构如下:

    (这个内存结构图分成了两个部分,上面是内存分布,下面是虚表,我们逐个看。VS所带编译器是把虚表指针放在了内存的开始处(0地址偏移),然后再是成员变量;

    下面生成了虚表,紧跟在&B_meta后面的0表示,这张虚表对应的虚指针在内存中的分布,下面列出了虚函数,左侧的0是这个虚函数的序号,这里只有一个虚函数,所以只有一项,如果有多个虚函数,会有序号为1,为2的虚函数列出来。)

    而A对象的内存结构如下:

    可见d只能找到a和A类的析构函数(因为d指向类A的指针),而无法找到B对象的析构函数,所以当delete d;的时候,B对象所占用的内存就此被泄漏掉了,也从而产生了异常。

     如果将A类的析构函数设为虚的,那么A类对象的内存结构将为:

     

    B类对象的内存结构为:

    (自己批注:注意:这里的B和A的析构函数的名字不一样, 不要和"多态里子类重写父类函数时(两者的函数名是一样的),子类虚函数表中内容会被修改掉"混淆了)

    此时通过A* d = new B();,A对象的内存结构中的vfptr,即虚函数表指针,就是B对象的vfptr(B对象的vfptr被bitwise copy,即浅拷贝到A对象的vfptr。(why?,有兴趣看下)如B是从A虚继承而来的,则需要加一个offset,情况要更复杂,见

    http://blog.csdn.net/pathuang68/archive/2009/04/24/4105902.aspx),因此,A对象的vfptr所指向的是B对象的虚函数表,而B的析构函数位于虚函数表0的位置,因此,这样就可以通过A类对象的指针d,找到B类对象的析构函数,从而在delete d;时,可以销毁B对象,而不会产生内存泄漏和异常。


    事实上,该题目只要将A中的析构函数设成虚的,B类中的析构函数前面的virtual关键字不管是否存在,其析构函数也一定是虚的,C类同此道理。因此,得到结论就是,只要能够保证继承关系中最高的基类的析构函数是虚的,那么就不会产生前面所谈及的问题。这就是为什么在想使用多态特性的时候,需要将基类的析构函数设成虚的真正原因。

    拓展好文章:

    C++类内存分布:https://www.cnblogs.com/jerry19880126/p/3616999.html

    新战场:https://blog.csdn.net/Stephen___Qin
  • 相关阅读:
    【Java8】 @FunctionalInterface 函数式接口
    集合使用copy与mutableCopy的区别
    GCD中的dispatch_sync、dispatch_sync 分别与串行、并行队列组合执行小实验
    podspec文件介绍
    iOS系统app崩溃日志手动符号化
    webView文本长按显示英文
    深拷贝
    view向全屏延伸时的属性设置
    iOS 模拟器截屏快捷键
    mysql 优化常用语句
  • 原文地址:https://www.cnblogs.com/Stephen-Qin/p/11509407.html
Copyright © 2011-2022 走看看