面试题答案
一键面试-
delete arr[0];
:- 内存释放:
arr[0]
指向Base
类型的对象,delete arr[0];
会释放arr[0]
所指向的Base
对象的内存。由于Base
有虚析构函数,析构函数会被正确调用。 - 析构函数调用:
Base
的虚析构函数会被调用,因为Base
类定义了虚析构函数,这确保了在通过基类指针删除对象时,能正确调用到Base
类的析构函数,从而正确清理Base
对象的资源。
- 内存释放:
delete[] arr;
:- 内存释放:
delete[] arr;
试图释放arr
所指向的数组内存。但是,数组中的元素是Base*
类型的指针,这个操作并不会直接释放arr[0]
和arr[1]
所指向的对象的内存。这会导致内存泄漏,因为arr[0]
和arr[1]
所指向的对象的内存没有被释放。 - 析构函数调用:由于
delete[] arr;
没有直接释放arr[0]
和arr[1]
所指向的对象的内存,所以不会调用Base
和Derived
的析构函数,进一步加剧了内存泄漏问题。
- 内存释放:
-
正确释放内存的方法:
- 代码实现:
#include <iostream>
class Base {
public:
virtual ~Base() {
std::cout << "Base destructor" << std::endl;
}
};
class Derived : public Base {
private:
int* data;
public:
Derived() {
data = new int(0);
}
~Derived() {
std::cout << "Derived destructor" << std::endl;
delete data;
}
};
int main() {
Base** arr = new Base*[2];
arr[0] = new Base();
arr[1] = new Derived();
for (int i = 0; i < 2; ++i) {
delete arr[i];
}
delete[] arr;
return 0;
}
- 内存布局:
arr
是一个指向Base*
类型数组的指针。数组中有两个元素,arr[0]
指向Base
对象,arr[1]
指向Derived
对象。Base
对象和Derived
对象在内存中是独立分配的。Derived
对象的内存布局首先是Base
部分(继承自Base
类),然后是Derived
类自己额外的数据成员(如int* data
)。
- 虚函数表:
Base
类有虚析构函数,这意味着Base
类有一个虚函数表(vtable)。Derived
类继承自Base
类,它也有自己的虚函数表,并且在Derived
的虚函数表中,虚析构函数的指针指向Derived
类的析构函数。当通过Base*
指针调用虚析构函数时,程序会根据对象实际的类型(通过虚函数表指针找到对应的虚函数表)来调用正确的析构函数。
- 析构函数调用顺序:
- 当
delete arr[0];
时,由于arr[0]
指向Base
对象,Base
的虚析构函数被调用。 - 当
delete arr[1];
时,因为arr[1]
指向Derived
对象,通过虚函数表,Derived
的析构函数首先被调用。在Derived
的析构函数执行完毕后,Base
的析构函数会被调用,因为Derived
类继承自Base
类,Base
类的析构函数会负责清理Base
部分的资源。最后,delete[] arr;
释放arr
所指向的数组内存,至此所有资源都被正确清理。
- 当