面试题答案
一键面试虚析构函数对资源释放的影响
当Base类析构函数声明为虚函数时,在通过基类指针删除派生类对象时,会调用派生类的析构函数,进而保证派生类中动态分配的资源也能正确释放。这是因为虚函数机制会根据对象的实际类型(而非指针类型)来调用合适的析构函数。
如果Base类析构函数不是虚函数,通过基类指针删除派生类对象时,只会调用基类的析构函数,派生类的析构函数不会被调用,从而导致派生类中动态分配的资源无法释放,造成内存泄漏。
代码实现
#include <iostream>
class Base {
public:
Base() {
dataBase = new int[10];
std::cout << "Base constructor" << std::endl;
}
// 虚析构函数
virtual ~Base() {
delete[] dataBase;
std::cout << "Base destructor" << std::endl;
}
private:
int* dataBase;
};
class Derived : public Base {
public:
Derived() {
dataDerived = new double[5];
std::cout << "Derived constructor" << std::endl;
}
~Derived() {
delete[] dataDerived;
std::cout << "Derived destructor" << std::endl;
}
private:
double* dataDerived;
};
// 非虚析构函数情况导致内存泄漏示例
class BaseNoVirtual {
public:
BaseNoVirtual() {
dataBase = new int[10];
std::cout << "BaseNoVirtual constructor" << std::endl;
}
// 非虚析构函数
~BaseNoVirtual() {
delete[] dataBase;
std::cout << "BaseNoVirtual destructor" << std::endl;
}
private:
int* dataBase;
};
class DerivedNoVirtual : public BaseNoVirtual {
public:
DerivedNoVirtual() {
dataDerived = new double[5];
std::cout << "DerivedNoVirtual constructor" << std::endl;
}
~DerivedNoVirtual() {
delete[] dataDerived;
std::cout << "DerivedNoVirtual destructor" << std::endl;
}
private:
double* dataDerived;
};
测试代码
int main() {
// 虚析构函数情况,资源正常释放
Base* basePtr = new Derived();
delete basePtr;
// 非虚析构函数情况,导致内存泄漏
BaseNoVirtual* baseNoVirtualPtr = new DerivedNoVirtual();
delete baseNoVirtualPtr;
return 0;
}
在上述代码中,Base
类有虚析构函数,BaseNoVirtual
类没有虚析构函数。在main
函数中,分别演示了两种情况下对象的创建和删除。虚析构函数的情况下,派生类对象内存正常释放;非虚析构函数情况下,派生类中动态分配的资源会泄漏。