什么时候使用虚析构函数

2022-02-10 19:05:35 浏览数 (1)

问题

什么时候该定义虚析构函数,为什么要这么做?

回答

当你通过一个基类指针去删除(delete)派生对象的时候,虚析构函数就很用了。

代码语言:javascript复制
#include <iostream>

using namespace std;

class Base
{
public:
    Base(){
        cout << "Base Constructor Calledn";
    }
    ~Base(){
        cout << "Base Destructor calledn";
    }
};

class Derived1: public Base
{
public:
    Derived1(){
        cout << "Derived constructor calledn";
    }
    ~Derived1(){
        cout << "Derived destructor calledn";
    }
};

int main()
{
    Base *b = new Derived1();
    delete b;
}

注意,我并没有把类 Base 的析构函数定义为虚(virtual)。输出如下:

代码语言:javascript复制
Base Constructor Called
Derived constructor called
Base Destructor called

我们发现派生类的析构函数并没有调用,这是有问题的,有可能会造成内存泄漏,而解决这个问题的办法就是将 Base 的析构函数定义为虚(virtual),

代码语言:javascript复制
class Base
{ 
public:
    Base(){
        cout << "Base Constructor Calledn";
    }
    virtual ~Base(){
        cout << "Base Destructor calledn";
    }
};

输出如下:

代码语言:javascript复制
Base Constructor Called
Derived Constructor called
Derived destructor called
Base destructor called

总结起来就是:当你的程序满足以下任何一项时,都无需定义基类虚拟析构函数,否则你就应该定义为虚,

  1. 这个基类没有派生类
  2. 不在堆(heap)内存实例化
  3. 没有指向派生类的基类指针或引用

对于 1,还是很常见的,有的时候我们只是单纯的写一个类,并没有派生它的打算,那这个时候就无需将它的析构函数定义为虚(virtual)了。

对于 2,基本上是个工程项目都不太可能,哪有一次都不在堆(heap)上实例化对象的,我是没遇到过,肯定是有一些对象必须要堆上实例化的。

对于 3,基本上也不太可能,派生类的存在基本上都会用到它的基类指针和引用。

0 人点赞