MST

星途 面试题库

面试题:C++ 虚基类析构在多重继承与动态内存管理下的复杂情况

在一个存在虚基类的复杂 C++ 项目中,有一个虚基类 Base,多个派生类 Derived1、Derived2 等继承自 Base,并且在这些派生类中有动态分配的内存(如通过 new 分配的数组或自定义对象)。在不同的多重继承场景下(例如菱形继承结构以及更复杂的多层继承结构),如何保证虚基类及其派生类析构函数正确释放动态分配的内存,避免内存泄漏?请详细阐述你的思路,并给出可能涉及的代码示例及解释。
33.2万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

思路

  1. 虚析构函数:在虚基类 Base 中定义虚析构函数。这确保在通过基类指针删除对象时,会调用正确的派生类析构函数,从而释放派生类中动态分配的内存。
  2. 遵循资源获取即初始化(RAII)原则:对于派生类中动态分配的内存,使用智能指针(如 std::unique_ptrstd::shared_ptr)来管理,这样在对象析构时,智能指针会自动释放所管理的资源。
  3. 多重继承场景处理:在菱形继承结构或更复杂的多层继承结构中,确保每个派生类的析构函数正确调用其直接基类的析构函数。由于虚基类只会被初始化一次,所以虚基类的析构函数也只会被调用一次,并且是在最底层派生类析构时调用。

代码示例

#include <iostream>
#include <memory>

class Base {
public:
    // 虚析构函数
    virtual ~Base() {
        std::cout << "Base destructor" << std::endl;
    }
};

class Derived1 : virtual public Base {
private:
    // 使用 std::unique_ptr 管理动态分配的内存
    std::unique_ptr<int[]> data1;
public:
    Derived1(int size) : data1(std::make_unique<int[]>(size)) {
        std::cout << "Derived1 constructor" << std::endl;
    }
    ~Derived1() {
        std::cout << "Derived1 destructor" << std::endl;
    }
};

class Derived2 : virtual public Base {
private:
    std::unique_ptr<int[]> data2;
public:
    Derived2(int size) : data2(std::make_unique<int[]>(size)) {
        std::cout << "Derived2 constructor" << std::endl;
    }
    ~Derived2() {
        std::cout << "Derived2 destructor" << std::endl;
    }
};

class FinalDerived : public Derived1, public Derived2 {
public:
    FinalDerived(int size) : Derived1(size), Derived2(size) {
        std::cout << "FinalDerived constructor" << std::endl;
    }
    ~FinalDerived() {
        std::cout << "FinalDerived destructor" << std::endl;
    }
};

解释

  1. 虚基类 Base:定义了虚析构函数,保证在删除 Base 指针指向的对象时,能正确调用派生类析构函数。
  2. 派生类 Derived1Derived2:使用 std::unique_ptr 管理动态分配的数组,遵循 RAII 原则,自动释放内存。
  3. 最终派生类 FinalDerived:通过多重继承从 Derived1Derived2 继承,由于 Derived1Derived2 虚继承自 BaseBase 只会被初始化一次。在 FinalDerived 对象析构时,会按照正确的顺序调用 FinalDerivedDerived1Derived2Base 的析构函数,从而确保所有动态分配的内存都被正确释放,避免内存泄漏。