MST

星途 面试题库

面试题:C++中为何有时需要为类定义虚析构函数

假设有一个基类`Base`和一个派生类`Derived`,`Base`类中有一些资源需要在析构时释放,派生类`Derived`也有额外资源需要释放。如果`Base`类的析构函数不是虚函数,在通过`Base`指针删除`Derived`对象时会发生什么?请通过代码示例说明为什么有时需要将`Base`类的析构函数定义为虚函数。
31.3万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试
  1. Base类析构函数不是虚函数时的情况
    • 当通过Base指针删除Derived对象且Base类析构函数不是虚函数时,只会调用Base类的析构函数,Derived类的析构函数不会被调用,这会导致Derived类中申请的资源无法释放,从而产生内存泄漏。
    • 以下是代码示例:
#include <iostream>
class Base {
public:
    Base() { std::cout << "Base constructor" << std::endl; }
    ~Base() { std::cout << "Base destructor" << std::endl; }
};
class Derived : public Base {
public:
    Derived() { std::cout << "Derived constructor" << std::endl; }
    ~Derived() { std::cout << "Derived destructor" << std::endl; }
};
int main() {
    Base* ptr = new Derived();
    delete ptr;
    return 0;
}
  • 在上述代码中,Base类的析构函数不是虚函数。当执行delete ptr;时,只会调用Base类的析构函数,输出为:
Base constructor
Derived constructor
Base destructor
  • 可以看到Derived类的析构函数没有被调用。
  1. Base类析构函数定义为虚函数的情况
    • 当把Base类的析构函数定义为虚函数时,通过Base指针删除Derived对象,会先调用Derived类的析构函数,再调用Base类的析构函数,这样就能正确释放Derived类和Base类中申请的资源。
    • 修改后的代码如下:
#include <iostream>
class Base {
public:
    Base() { std::cout << "Base constructor" << std::endl; }
    virtual ~Base() { std::cout << "Base destructor" << std::endl; }
};
class Derived : public Base {
public:
    Derived() { std::cout << "Derived constructor" << std::endl; }
    ~Derived() { std::cout << "Derived destructor" << std::endl; }
};
int main() {
    Base* ptr = new Derived();
    delete ptr;
    return 0;
}
  • 此时执行delete ptr;,输出为:
Base constructor
Derived constructor
Derived destructor
Base destructor
  • 可以看到Derived类的析构函数被正确调用,资源得到了正确释放。

所以,为了确保通过基类指针删除派生类对象时,派生类的析构函数能被正确调用,防止内存泄漏,有时需要将Base类的析构函数定义为虚函数。