面试题答案
一键面试- 资源释放顺序:
- 当子类对象被析构时,首先会调用子类的析构函数。在子类析构函数中,会先释放子类自己动态分配的资源。
- 然后,父类的析构函数会被自动调用,用于释放父类中动态分配的资源。这是因为析构函数的调用顺序与构造函数相反,构造函数是先调用父类构造函数再调用子类构造函数,而析构函数是先调用子类析构函数再调用父类析构函数。
- 内存管理要点:
- 确保析构函数正确实现:在父类和子类的析构函数中,要正确地释放各自动态分配的资源,避免内存泄漏。对于使用
new
分配的内存,要使用delete
释放;对于使用new[]
分配的数组内存,要使用delete[]
释放。 - 父类析构函数应声明为虚函数:如果父类析构函数不是虚函数,当通过父类指针删除子类对象时,只会调用父类的析构函数,子类的析构函数不会被调用,从而导致子类动态分配的资源无法释放,产生内存泄漏。
- 确保析构函数正确实现:在父类和子类的析构函数中,要正确地释放各自动态分配的资源,避免内存泄漏。对于使用
- 代码示例:
#include <iostream>
#include <cstring>
class Parent {
public:
Parent(const char* name) {
this->name = new char[strlen(name) + 1];
strcpy(this->name, name);
}
// 声明为虚析构函数
virtual ~Parent() {
std::cout << "Parent destructor: releasing " << name << std::endl;
delete[] name;
}
private:
char* name;
};
class Child : public Parent {
public:
Child(const char* name, int id) : Parent(name) {
this->id = new int;
*this->id = id;
}
~Child() {
std::cout << "Child destructor: releasing id " << *id << std::endl;
delete id;
}
private:
int* id;
};
int main() {
Parent* p = new Child("John", 10);
delete p;
return 0;
}
在上述代码中:
Parent
类动态分配了一个字符数组用于存储名字,并在其析构函数中释放该数组。Child
类继承自Parent
类,动态分配了一个整数用于存储ID,并在其析构函数中释放该整数。Parent
类的析构函数声明为虚函数,确保通过父类指针删除子类对象时,子类的析构函数也能被调用,从而正确释放所有动态分配的资源。