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. 拥有纯虚析构函数的类也属于抽象类

 

posted @   安静点--  阅读(95)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示