zoukankan      html  css  js  c++  java
  • 【C++】C++中基类的析构函数为什么要用virtual虚析构函数?

    正面回答:

    当基类的析构函数不是虚函数,并且基类指针指向一个派生类对象,然后通过基类指针来删除这个派生类对象时,如果基类的析构函数不是虚析构函数,那么派生类的析构函数就不会被调用,从而产生内存泄漏

    #include<iostream>
    #include<bits/stdc++.h>
    using namespace std;
    
    class A
    {
    public:
        A()
        {
            cout<<"constructing A"<<endl;
        }
        ~A()
        {
            delete p;
            cout<<"destructing A"<<endl;
        }
    private:
        int *p;
    };
    
    class B:public A
    {
    public:
        B()
        {
            cout<<"constructing B"<<endl;
        }
        ~B()
        {
            delete p;
            cout<<"destructing B"<<endl;
        }
    private:
        int *p;
    };
    
    int main()
    {
    
        A *a=new B();
        delete a;
    }
    /*
    constructing A
    constructing B
    destructing A
    */

    分析:只调用了基类A的析构函数,而派生类B的析构函数却没有被调用,这时会产生内存泄漏

    如果给基类A的析构函数是虚析构函数,那么便不会产生这个问题

    #include<iostream>
    #include<bits/stdc++.h>
    using namespace std;
    
    class A
    {
    public:
        A()
        {
            cout<<"constructing A"<<endl;
        }
        virtual ~A()
        {
            delete p;
            cout<<"destructing A"<<endl;
        }
    private:
        int *p;
    };
    
    class B:public A
    {
    public:
        B()
        {
            cout<<"constructing B"<<endl;
        }
        ~B()
        {
            delete p;
            cout<<"destructing B"<<endl;
        }
    private:
        int *p;
    };
    
    int main()
    {
    
        A *a=new B();
        delete a;
    }
    /*
    constructing A
    constructing B
    destructing B
    destructing A
    */

    此时派生类B的析构函数被调用了!内存泄漏的问题得以解决

    注意构造函数和析构函数的执行顺序:

    派生类构造时:先执行基类的构造函数,然后执行派生类的构造函数

    派生类析构时:先执行派生类的析构函数,然后执行基类的析构函

    上面内存泄漏产生的必要条件:

    1.基类析构函数不是虚析构函数

    2.派生类对象的析构函数中有内存需要回收

    3.基类指针指向派生类对象,通过删除该基类指针来删除派生类对象

    那这种情况下为什么会产生内存泄漏呢?

    这种情况下,当删除基类指针指向的派生类对象时不会触发动态绑定,虚函数是动态绑定的基础,现在基类的析构函数不是虚函数,所以不会发生动态绑定,而是静态绑定,指针的静态类型为基类类型,所以delete的时候只会调用基类的析构函数

    结论:

    人生建议,继承时,基类的析构函数中最好加上virtual。


  • 相关阅读:
    Delete 语句带有子查询的sql优化
    标量子查询SQL改写
    自定义函数导致的sql性能问题
    Oracle 11G RAC For ASM 利用RMAN COPY进行存储迁移
    WPF 如何控制右键菜单ContextMenu的弹出
    将字符串以用二进制流的形式读入XML文件
    WPF 将数据源绑定到TreeView控件出现界面卡死的情况
    WPF如何实现TreeView节点重命名
    Azure一个Cloud Service支持多个公网地址
    Azure上部署Barracuda WAF集群 --- 2
  • 原文地址:https://www.cnblogs.com/yinbiao/p/11613359.html
Copyright © 2011-2022 走看看