MST

星途 面试题库

面试题:C++虚析构函数与内存管理

考虑一个复杂的C++继承体系,其中基类Base包含动态分配的资源(如通过new分配的数组)。派生类Derived在此基础上添加了更多动态分配的资源。请详细阐述将Base类析构函数声明为虚函数对整个对象生命周期内资源释放的影响,并且写出完整的代码实现,包括资源的分配与释放,以及在不同情况下(析构函数为虚和非虚)可能出现的内存泄漏问题。
25.4万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

虚析构函数对资源释放的影响

当Base类析构函数声明为虚函数时,在通过基类指针删除派生类对象时,会调用派生类的析构函数,进而保证派生类中动态分配的资源也能正确释放。这是因为虚函数机制会根据对象的实际类型(而非指针类型)来调用合适的析构函数。

如果Base类析构函数不是虚函数,通过基类指针删除派生类对象时,只会调用基类的析构函数,派生类的析构函数不会被调用,从而导致派生类中动态分配的资源无法释放,造成内存泄漏。

代码实现

#include <iostream>

class Base {
public:
    Base() {
        dataBase = new int[10];
        std::cout << "Base constructor" << std::endl;
    }
    // 虚析构函数
    virtual ~Base() {
        delete[] dataBase;
        std::cout << "Base destructor" << std::endl;
    }
private:
    int* dataBase;
};

class Derived : public Base {
public:
    Derived() {
        dataDerived = new double[5];
        std::cout << "Derived constructor" << std::endl;
    }
    ~Derived() {
        delete[] dataDerived;
        std::cout << "Derived destructor" << std::endl;
    }
private:
    double* dataDerived;
};

// 非虚析构函数情况导致内存泄漏示例
class BaseNoVirtual {
public:
    BaseNoVirtual() {
        dataBase = new int[10];
        std::cout << "BaseNoVirtual constructor" << std::endl;
    }
    // 非虚析构函数
    ~BaseNoVirtual() {
        delete[] dataBase;
        std::cout << "BaseNoVirtual destructor" << std::endl;
    }
private:
    int* dataBase;
};

class DerivedNoVirtual : public BaseNoVirtual {
public:
    DerivedNoVirtual() {
        dataDerived = new double[5];
        std::cout << "DerivedNoVirtual constructor" << std::endl;
    }
    ~DerivedNoVirtual() {
        delete[] dataDerived;
        std::cout << "DerivedNoVirtual destructor" << std::endl;
    }
private:
    double* dataDerived;
};

测试代码

int main() {
    // 虚析构函数情况,资源正常释放
    Base* basePtr = new Derived();
    delete basePtr;

    // 非虚析构函数情况,导致内存泄漏
    BaseNoVirtual* baseNoVirtualPtr = new DerivedNoVirtual();
    delete baseNoVirtualPtr;

    return 0;
}

在上述代码中,Base类有虚析构函数,BaseNoVirtual类没有虚析构函数。在main函数中,分别演示了两种情况下对象的创建和删除。虚析构函数的情况下,派生类对象内存正常释放;非虚析构函数情况下,派生类中动态分配的资源会泄漏。