引言
在普通类继承里,删除子类对象会先调用子类的析构,再调用父类的析构。但在多态里情况有所不同。我们删除的是父类指针,调用的只是父类的析构函数,子类析构不会被调用,也就是说,子类对象没有被删除,而指针却没了。这是局部销毁,会造成资源泄漏等错误;
虚析构函数
当通过基类指针删除对象时,应该确保可以调用派生类的析构函数,为实现该目的,可以使用类的虚析构函数;
在基类中声明析构函数为虚函数。如果基类的析构函数是虚拟的,删除基类指针时,C++ 会确保首先调用派生类的析构函数,然后再调用基类的析构函数。这是确保对象正确销毁的关键;
代码示例:
#include <iostream>
class Base {
public:
Base() { std::cout << "Base constructor\n"; }
~Base() { std::cout << "Base destructor\n"; }
};
class Derived : public Base {
public:
Derived() { std::cout << "Derived constructor\n"; }
~Derived() { std::cout << "Derived destructor\n"; }
};
int main() {
Base* b = new Derived();
delete b; // 如果 Base 没有虚析构函数,只会调用 Base 的析构函数
return 0;
}
当Base类的构造函数不是虚函数时的输出结果:
Base constructor
Derived constructor
Base destructor
可以看出只会调用基类的析构函数,而子类的析构函数并没有调用,子类对象没有被删除,导致内存泄漏;针对该问题,可以通过将基类的构造函数修正为虚析构函数:
class Base {
public:
Base() { std::cout << "Base constructor\n"; }
virtual ~Base() { std::cout << "Base destructor\n"; } // 声明为虚析构函数
};
Base类的构造函数为虚析构函数时的输出结果:
Base constructor
Derived constructor
Derived destructor
Base destructor