首页 > 编程笔记

C++虚析构函数详解

在C++中,当一个基类指针指向派生类对象,通过这个基类指针删除对象时,如果基类的析构函数不是虚函数,会导致派生类的析构函数不被调用,从而引发资源泄漏和不正确的行为。

例如,分析下面的程序:
#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 类和 Derived 类分别具有构造函数和析构函数。使用 Base 类的指针指向 Derived 类的对象,并使用 delete 关键字删除对象。

执行结果为:

Base constructor
Derived constructor
Base destructor

可以看到,Derived 类的析构函数没有被正确调用,导致资源泄漏和不确定的行为。

在 C++ 中,通过指针访问非虚函数时,编译器会根据指针的类型来确定要调用的函数。示例程序中,ptr 是基类的指针,所以直接调用的是基类的析构函数。

修改上面的程序,将基类的析构函数改为虚析构函数,即用 virtual 修饰析构函数:
virtual ~Base() {
    std::cout << "Base destructor" << std::endl;
}
注意,设置基类的析构函数为虚函数,则所有派生类的析构函数都自动变为虚函数。再次运行程序:

Base constructor
Derived constructor
Derived destructor
Base destructor

可以看到,基类指针删除对象时会正确调用派生类的析构函数,从而释放对象的资源。

总结

在 C++ 中,通过声明基类的析构函数为虚函数,确保通过基类指针删除对象时能够正确调用派生类的析构函数,从而避免资源泄漏和不确定的行为。

推荐阅读