C++虚析构函数_很重要

本文通过实例展示了C++中虚析构函数的作用,解释了为何在基类中声明虚析构函数是必要的。当基类指针指向派生类对象时,若基类析构函数为虚函数,可以确保派生类的析构函数也被调用,从而正确释放内存,避免内存泄漏问题。否则,派生类的资源可能无法得到释放,导致程序出现内存泄漏。
部署运行你感兴趣的模型镜像

C++虚析构函数_很重要

C++虚析构函数(很重要)

#include<iostream>
using namespace std;

class base
{
public:
    base();
    ~base();
private:
    int * a;
};

class derived: public base
{
public:
    derived();
    ~derived();
private:
    int * b;
};

base::base()
{
    cout<<"base constructor!"<<endl;
    a = new int[10];
}

base::~base()
{
    cout<<"base destructor!"<<endl;
    delete[] a;
}

derived::derived()
{
    cout<<"derived constructor!"<<endl;
    b = new int[1000];
}

derived::~derived()
{
    cout<<"derived destructor!"<<endl;
    delete[] b;
}

int main()
{
    base* p;
    p = new derived;
    delete p;
    return 0;
}

在本例中,派生类和基类中都分别定义了自己的构造函数和析构函数,它们各有一个 int 型指针成员变量,并且:
1.在基类的构造函数中,给指针变量 a 分配了 10 个 int 型空间,在基类的析构函数则用于将是将 a 所指向的空间释放掉;
2.在派生类的构造函数中,指针成员变量被分配了 1000 个整型空间,派生类的析构函数则是为了释放掉 b 指针所指向的存储空间。
在主函数中,我们创建一个基类类型的指针,指针指向一个派生类对象,之后释放 p 指针所指向的对象的存储空间。最后程序运行结果如下:
在这里插入图片描述
当我们用 new 操作符创建一个派生类对象时会先调用基类构造函数,然后再调用派生类构造函数。观察程序运行结果,程序打印出了“base constructor!”这串字符,则说明基类的构造函数被调用了,之后又打印出了“derived constructor!”这串字符,同样地派生类的构造函数也被调用了,程序输出结果与我们料想的是一致的。

之后程序打印出了“base destructor!”字符串,这说明基类的析构函数被调用了,a 指针所指向的 10 个整型内存空间被释放了。但是之后却并未调用派生类的析构函数,这意味着 b 指针所指向的 1000 个整型存储空间没有被释放,如此一来就造成了内存泄露。

内存泄露问题肯定是我们程序设计人员需要极力避免的。本例中出现内存泄漏问题,是因为派生类的析构函数未被调用。为了解决这个问题,我们将基类的析构函数声明为虚函数,修改后基类的定义如下:

class base
{
public:
    base();
    virtual ~base();
private:
    int * a;
};

完整代码

#include<iostream>
using namespace std;

class base
{
public:
    base();
    virtual ~base();
private:
    int * a;
};

class derived: public base
{
public:
    derived();
    ~derived();
private:
    int * b;
};

base::base()
{
    cout<<"base constructor!"<<endl;
    a = new int[10];
}

base::~base()
{
    cout<<"base destructor!"<<endl;
    delete[] a;
}

derived::derived()
{
    cout<<"derived constructor!"<<endl;
    b = new int[1000];
}

derived::~derived()
{
    cout<<"derived destructor!"<<endl;
    delete[] b;
}

int main()
{
    base* p;
    p = new derived;
    delete p;
    return 0;
}

修改基类的定义后,程序运行结果如下:

base constructor!
derived constructor!
derived destructor!
base destructor!

将基类的析构函数声明为虚函数之后,派生类的析构函数也自动成为虚析构函数。在主函数中,基类指针 p 指向的是派生类对象,当 delete 释放 p 指针所指向的存储空间时,会执行派生类的析构函数,派生类的析构函数执行完之后会紧接着执行基类的析构函数,以释放从基类继承过来的成员变量所消耗的资源。如此一来就不会存在内存泄漏问题了。

从此例中,我们很明显可以看出析构函数声明为虚函数的必要性。但是,如果不管三七二十一的将所有的基类的析构函数都声明为虚函数,这也是不合适的。通常来说,如果派生类中存在一个指向动态分配内存的成员变量,并且派生类的析构函数中定义了释放该动态分配内存的代码,则应该将基类的析构函数声明为虚函数。

reference

C++虚析构函数

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

静思心远

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值