C++多态之虚析构与纯虚析构

一、虚析构纯虚析构的共同点:

  1. 都是释放子类的堆区资源。
  2. 都需要具体实现。

二、虚析构纯虚析构的不同点: 

  1. 使用纯虚析构函数的父类属于抽象类,不能实例化具体对象。代码示例如下:
    #include <iostream>
    
    // 父类
    class Base
    {
        public:
            
            // 纯虚析构函数
            virtual ~Base() = 0;
    
    };
    
    // 纯虚析构函数的实现,此处必须实现,因为是析构函数,可能会释放父类的堆区资源,否则代码会报错
    Base::~Base()
    {
        std::cout << "父类的纯虚析构函数调用" << std::endl;
    }
    
    class Son : public Base
    {
        public:
            
            // 子类析构函数的实现
            virtual ~Son()
            {
                std::cout << "子类的析构函数调用" << std::endl;
            }
    };
    
    int main()
    {
        // 实例化失败,此处代码会报错,因为父类有纯虚析构函数,是抽象类
        // Base * base = new Base;
    
        // 实例化成功,因为子类不是抽象类
        Base * base = new Son;
    
        system("pause");
        return 0;
    }
  2. 使用虚析构函数的父类不属于抽象类,可以实例化具体对象。代码实例如下:
    #include <iostream>
    
    class Father
    {
        public:
            
            // 父类的虚析构函数
            virtual ~Father()
            {
                std::cout << "父类的虚析构函数调用" << std::endl;
            }
    
    };
    
    int main()
    {
        // 此时父类实例化成功,因为父类不是抽象类,代码不会报错
        Father * father = new Father;
    
        system("pause");
        return 0;
    }

 三、虚析构纯虚析构的作用

解决父类指针父类引用无法释放子类资源导致的内存泄露问题 。

现在可以来做个对比,首先写一个无虚析构或无纯虚析构的父类代码案例,看看最后的打印信息

  • 无虚析构或无纯虚析构的父类代码案例:

#include <iostream>
using namespace std;

class Father
{
    public:
        
        // 父类的析构函数
        ~Father()
        {
            std::cout << "父类的析构函数调用" << std::endl;
        }
};

class Son : public Father
{
    public:
        
        // 子类的析构函数
        ~Son()
        {
            std::cout << "子类的析构函数调用" << std::endl;
        }
};

int main()
{
    Father * father = new Son;
    delete father;

    system("pause");
    return 0;
}

 运行结果截图如下,可见未调用子类的析构函数,如果此时的子类申请了堆区资源,必将造成内存泄露问题:

  •  有虚析构或纯虚析构的父类代码案例

#include <iostream>

class Father
{
    public:
        
        // 父类的构造函数
        Father()
        {
            std::cout << "父类的构造函数调用" << std::endl;
        }

        // 父类的虚析构函数
        virtual ~Father()
        {
            std::cout << "父类的虚析构函数调用" << std::endl;
        }

};

class Son : public Father
{
    public:
        
        // 子类的构造函数
        Son(std::string name)
        {
            std::cout << "子类构造函数的调用" << std::endl;

            // 子类申请堆区资源
            m_Name = new std::string(name);
        }

        ~Son()
        {

            std::cout << "子类析构函数的调用" << std::endl;

            // 析构子类的堆区资源
            if (m_Name != NULL)
            {
                delete m_Name;
                m_Name = NULL;
            }
        }

        // 此处为字符串指针变量,是为了申请堆区资源做准备
        std::string * m_Name;
};

int main()
{
    Father * father = new Son("Jack");
    delete father;

    system("pause");
    return 0;
}

 运行结果截图如下,在此段代码中,父类使用了虚析构函数,子类申请了堆区资源,在释放父类资源的同时也释放了子类资源。

 


如果喜欢此文章,可以点赞哦,我会无偿分享所有源码与自己的C++成长之路 !

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值