• c++虚析构和纯虚析构(可解决子类存在到堆区存储数据导致内存泄漏问题) 安静点


    虚析构和纯虚析构

    多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码

    解决方式:将父类中的析构函数改为虚析构或者纯虚析构

    虚析构和纯虚析构共性:

    • 可以解决父类指针释放子类对象
    • 都需要有具体的函数实现

    虚析构和纯虚析构区别:

    • 如果是纯虚析构,该类属于抽象类,无法实例化对象

    虚析构语法:

    virtual ~类名(){}

    纯虚析构语法:

    virtual ~类名() = 0;

    类名::~类名(){}

    示例:

    class Animal {
    public:
    
        Animal()
        {
            cout << "Animal 构造函数调用!" << endl;
        }
        virtual void Speak() = 0;
    
        //析构函数 
          ~Animal()
        {
            cout << "Animal虚析构函数调用!" << endl;
        }
         
    };
     
    class Cat : public Animal {
    public:
        Cat(string name)
        {
            cout << "Cat构造函数调用!" << endl;
            m_Name = new string(name);
        }
        virtual void Speak()
        {
            cout << *m_Name << "小猫在说话!" << endl;
        }
        ~Cat()
        {
            //因为Cat类中m_Name在堆区创建了数据,所以必须要释放掉,避免内存泄漏,所以增加析构函数
            cout << "Cat析构函数调用!" << endl;
            if (this->m_Name != NULL) {
                delete m_Name;
                m_Name = NULL;
            }
        }
    
    public:
        string* m_Name;
    };
    
    void test01()
    {
        Animal* animal = new Cat("Tom");
        animal->Speak();
    
        //通过父类指针去释放,会导致子类对象可能清理不干净,造成内存泄漏 
        delete animal;
    }
    
    int main() {
    
        test01();
    
        system("pause");
    
        return 0;
    }

    结果:

     可以看到Cat的析构函数没有调用,应该在父类Animal之前调用子类Cat的析构函数的。通过父类指针去释放,会导致子类对象可能清理不干净,造成内存泄漏

     怎么解决?

    给基类增加一个虚析构函数,虚析构函数就是用来解决通过父类指针释放子类对象

     示例:

    class Animal {
    public:
    
        Animal()
        {
            cout << "Animal 构造函数调用!" << endl;
        }
        virtual void Speak() = 0;
    
        //析构函数  析构函数加上virtual关键字,变成虚析构函数
        virtual ~Animal()
        {
            cout << "Animal虚析构函数调用!" << endl;
        }
         
    };
     
    class Cat : public Animal {
    public:
        Cat(string name)
        {
            cout << "Cat构造函数调用!" << endl;
            m_Name = new string(name);
        }
        virtual void Speak()
        {
            cout << *m_Name << "小猫在说话!" << endl;
        }
        ~Cat()
        {
            //因为Cat类中m_Name在堆区创建了数据,所以必须要释放掉,避免内存泄漏,所以增加析构函数
            cout << "Cat析构函数调用!" << endl;
            if (this->m_Name != NULL) {
                delete m_Name;
                m_Name = NULL;
            }
        }
    
    public:
        string* m_Name;
    };
    
    void test01()
    {
        Animal* animal = new Cat("Tom");
        animal->Speak();
    
        //通过父类指针去释放,会导致子类对象可能清理不干净,造成内存泄漏
        //怎么解决?给基类增加一个虚析构函数
        //虚析构函数就是用来解决通过父类指针释放子类对象
        delete animal;
    }
    
    int main() {
    
        test01();
    
        system("pause");
    
        return 0;
    }

     结果:

     还有一种方式,那就是改成纯虚析构,和包含普通纯虚函数的类一样,包含了纯虚析构函数的类也是一个抽象类。不能够被实例化。

    class Animal {
    public:
    
        Animal()
        {
            cout << "Animal 构造函数调用!" << endl;
        }
        virtual void Speak() = 0; 
        //纯虚析构函数声明
        virtual ~Animal() = 0;
    };
    
    //实现纯虚析构函数  必须要实现,不然报错!!!
    Animal::~Animal()
    {
        cout << "Animal 纯虚析构函数调用!" << endl;
    }
    
    //和包含普通纯虚函数的类一样,包含了纯虚析构函数的类也是一个抽象类。不能够被实例化。
    
    class Cat : public Animal {
    public:
        Cat(string name)
        {
            cout << "Cat构造函数调用!" << endl;
            m_Name = new string(name);
        }
        virtual void Speak()
        {
            cout << *m_Name << "小猫在说话!" << endl;
        }
        ~Cat()
        {
            cout << "Cat析构函数调用!" << endl;
            if (this->m_Name != NULL) {
                delete m_Name;
                m_Name = NULL;
            }
        }
    
    public:
        string* m_Name;
    };
    
    void test01()
    {
        Animal* animal = new Cat("Tom");
        animal->Speak();
    
        //通过父类指针去释放,会导致子类对象可能清理不干净,造成内存泄漏
        //怎么解决?给基类增加一个虚析构函数
        //虚析构函数就是用来解决通过父类指针释放子类对象
        delete animal;
    }
    
    int main() {
    
        test01();
    
        system("pause");
    
        return 0;
    }

     结果:

    总结:

    1. 虚析构或纯虚析构就是用来解决通过父类指针释放子类对象

    ​ 2. 如果子类中没有堆区数据,可以不写为虚析构或纯虚析构

    ​ 3. 拥有纯虚析构函数的类也属于抽象类

  • 相关阅读:
    softmax和cross_entropy
    python初始化list列表(1维、2维)
    奥卡姆剃刀 (Occam Razor)
    何谓超参数?
    面试干货!21个必知数据科学面试题和答案
    计算广告算法到底要做什么?
    推荐系统的常用算法
    推荐系统常见面试题2
    推荐系统算法面试题
    mysql-面试题
  • 原文地址:https://www.cnblogs.com/anjingdian/p/16127102.html
Copyright © 2020-2023  润新知