MST

星途 面试题库

面试题:C++指针在多态场景下的应用与内存管理

假设有一个基类`Base`和派生类`Derived`,在`Base`中有虚函数`virtual void func()`。现在通过`Base*`指针指向`Derived`对象,并调用`func`函数。请分析这个过程中指针的作用,以及可能涉及到的内存管理问题,同时写出相关代码示例,并说明如何避免内存泄漏。
24.7万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

指针作用

通过Base*指针指向Derived对象,利用了C++的多态性。该指针允许在运行时根据实际指向的对象类型来决定调用哪个版本的func函数。如果指向Base对象,则调用Base类的func函数;若指向Derived对象,就调用Derived类重写的func函数。

内存管理问题

  1. 对象创建与释放不匹配:如果通过new在堆上创建Derived对象,并用Base*指针指向它,释放时若使用delete Base*,而Base类的析构函数不是虚函数,那么只会调用Base类的析构函数,Derived类的析构函数不会被调用,可能导致Derived类中分配的资源无法释放,造成内存泄漏。

代码示例

#include <iostream>

class Base {
public:
    virtual void func() {
        std::cout << "Base::func()" << std::endl;
    }
    // 为避免内存泄漏,基类析构函数应设为虚函数
    virtual ~Base() {
        std::cout << "Base::~Base()" << std::endl;
    }
};

class Derived : public Base {
public:
    void func() override {
        std::cout << "Derived::func()" << std::endl;
    }
    ~Derived() override {
        std::cout << "Derived::~Derived()" << std::endl;
    }
};

int main() {
    Base* ptr = new Derived();
    ptr->func();
    delete ptr;
    return 0;
}

避免内存泄漏的方法

  1. 虚析构函数:在Base类中定义虚析构函数。这样,当通过Base*指针删除对象时,会先调用Derived类的析构函数,再调用Base类的析构函数,确保所有资源都被正确释放。如上述代码中Base类的虚析构函数~Base()
  2. 智能指针:使用智能指针(如std::unique_ptrstd::shared_ptr)来管理对象的生命周期。智能指针会在其作用域结束时自动释放所指向的对象,减少手动管理内存的错误。例如:
#include <iostream>
#include <memory>

class Base {
public:
    virtual void func() {
        std::cout << "Base::func()" << std::endl;
    }
    virtual ~Base() {
        std::cout << "Base::~Base()" << std::endl;
    }
};

class Derived : public Base {
public:
    void func() override {
        std::cout << "Derived::func()" << std::endl;
    }
    ~Derived() override {
        std::cout << "Derived::~Derived()" << std::endl;
    }
};

int main() {
    std::unique_ptr<Base> ptr = std::make_unique<Derived>();
    ptr->func();
    return 0;
}

在这个例子中,std::unique_ptr会在离开作用域时自动调用Derived对象的析构函数,从而避免内存泄漏。