MST
星途 面试题库

面试题:C++复杂继承体系及智能指针下虚析构函数调用顺序分析

给定如下复杂的C++继承体系和智能指针使用场景: class GrandParent { public: virtual ~GrandParent() { std::cout << "GrandParent destructor" << std::endl; } }; class Parent : public GrandParent { public: virtual ~Parent() { std::cout << "Parent destructor" << std::endl; } }; class Child : public Parent { public: ~Child() { std::cout << "Child destructor" << std::endl; } }; class OtherChild : public Parent { public: ~OtherChild() { std::cout << "OtherChild destructor" << std::endl; } }; class Composite : public Child, public OtherChild { public: ~Composite() { std::cout << "Composite destructor" << std::endl; } }; std::unique_ptr<GrandParent> GetComposite() { return std::make_unique<Composite>(); } int main() { auto ptr = GetComposite(); return 0; } 请详细分析在整个生命周期内,虚析构函数的调用顺序,以及智能指针管理对其的影响。
35.5万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试
  1. 虚析构函数调用顺序
    • main函数中ptr的生命周期结束时(main函数返回,ptr离开作用域),智能指针ptr会自动释放其所管理的对象。
    • 由于ptr指向的实际对象是Composite类型(通过GetComposite函数创建),首先调用Composite的析构函数。输出:Composite destructor
    • 因为Composite继承自ChildOtherChild,接下来会调用ChildOtherChild的析构函数。这里由于C++的多重继承特性,先调用Child的析构函数,输出:Child destructor,再调用OtherChild的析构函数,输出:OtherChild destructor
    • ChildOtherChild又都继承自Parent,所以会调用Parent的析构函数,输出:Parent destructor
    • Parent继承自GrandParent,最后调用GrandParent的析构函数,输出:GrandParent destructor
    • 总的调用顺序为:Composite destructor -> Child destructor -> OtherChild destructor -> Parent destructor -> GrandParent destructor
  2. 智能指针管理对其的影响
    • 使用std::unique_ptr管理对象,std::unique_ptr负责对象的自动释放。当std::unique_ptr离开其作用域(在main函数返回时ptr离开作用域),它会自动调用所管理对象的析构函数。
    • 这种自动管理机制确保了对象资源(例如动态分配的内存等)的正确释放,避免了内存泄漏。同时,由于std::unique_ptr指向的是GrandParent类型,通过虚析构函数机制,能够正确地调用到实际对象(Composite)及其所有基类的析构函数,保证了整个对象层次结构的正确销毁。如果没有虚析构函数,当通过GrandParent类型的指针(这里是std::unique_ptr<GrandParent>)释放对象时,只会调用GrandParent的析构函数,导致Composite及其其他基类的析构函数不会被调用,从而可能引发内存泄漏和未定义行为。

所以,智能指针std::unique_ptr结合虚析构函数,保证了复杂继承体系下对象生命周期的正确管理和资源的安全释放。