C++的虚析构详解及实例代码
什么是虚析构函数
在 C++ 中,如果一个类中含有虚函数,我们通常都会将这个类的析构函数定义为虚析构函数,以保证对象的正确释放。
虚析构函数是在基类中定义,被子类继承并覆盖的析构函数。具有虚析构函数的类被用做其他类的基类,以确保正确地释放对象的所有资源。
虚析构函数的应用场景
假设我们有一个基类Base
,它含有虚析构函数,另外还有一个派生类Derived
。在使用多态性功能时,派生类的指针可能会指向基类的对象。如果我们删除一个指向派生类对象的指针,而这个指针又是定义为基类类型的,那么删除时调用的就是基类的析构函数。这样就会造成内存泄漏,虚析构函数就是为了解决这个问题而设计的。
示例一:不定义虚析构函数的情况
#include<iostream>
using namespace std;
class A {
public:
A() {
cout << "A构造" << endl;
}
~A() {
cout << "A析构" << endl;
}
};
class B :public A {
public:
B() {
cout << "B构造" << endl;
data = new char[10];
}
~B() {
cout << "B析构" << endl;
delete[] data;
}
private:
char* data;
};
int main(int argc, char* argv[]) {
A* p = new B();
delete p;
return 0;
}
分析:上面的代码中,类A
是基类,派生类是B
。B
类中开辟了一段内存。在主函数中,使用基类指针指向派生类对象,并在结束前将这个指针指向的数据删除。根据我们刚才提到的规则,执行的是基类的析构函数,没有进行正确的释放,导致内存泄漏。
输出:
A构造
B构造
A析构
可以看出,由于没有定义虚析构函数,B
中分配的内存没有被释放。
示例二:定义虚析构函数的情况
#include<iostream>
using namespace std;
class A {
public:
A() {
cout << "A构造" << endl;
}
virtual ~A() {
cout << "A析构" << endl;
}
};
class B :public A {
public:
B() {
cout << "B构造" << endl;
data = new char[10];
}
~B() {
cout << "B析构" << endl;
delete[] data;
}
private:
char* data;
};
int main(int argc, char* argv[]) {
A* p = new B();
delete p;
return 0;
}
分析:这个代码和上面的示例一基本一致,不同的地方在于基类的析构函数是虚析构函数,这样就变成了动态绑定,能够在真正释放时调用基类中的虚析构函数,从而正确释放派生类的内存,避免了内存泄漏。
输出:
A构造
B构造
B析构
A析构
可以看出,开辟的内存得到了正确的释放。
总结
虚析构函数对于多态性非常重要,没有虚析构函数可能会导致程序运行结果不可预测甚至崩溃,建议在有虚函数的时候一定要定义虚析构函数。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++的虚析构详解及实例代码 - Python技术站