前言
本文主要探讨C++中虚析构函数的作用并结合一个简单的示例代码加以说明。
一、虚析构函数的作用是什么?
在C++中,如果基类的析构函数没有声明为虚函数的话,当使用 delete 操作符删除一个指向派生类对象的基类指针时,则只会调用基类的析构函数,而不会调用派生类的析构函数,这样就有可能会导致派生类的资源没有得到正确的释放从而造成内存泄漏。
二、基类中没有声明虚析构函数可能带来的问题
我们先看一下这个例子
#include <iostream>
#include <string.h>
using namespace std;
class Base {
public:
Base() {cout << "Base()" << endl;};
~Base() {cout << "~Base()" << endl;}
//virtual ~Base() {cout << "~Base()" << endl;}
virtual void DisplayData() = 0;
};
class Derive : public Base {
public:
Derive(const char* str = NULL);
~Derive();
void DisplayData() {
cout << "m_data: " << m_date << endl;
}
private:
char *m_date;
};
Derive::Derive(const char* str)
{
cout << "Derive()" << endl;
if (str != NULL) {
int length = strlen(str);
m_date = new char [length + 1];
strcpy(m_date, str);
} else {
m_date = new char [1];
*m_date = '\0';
}
}
Derive::~Derive()
{
cout << "~Derive()" << endl;
delete[] m_date;
}
int main(int argc, char *argv[])
{
Base *b_ptr = new Derive("hello world");
b_ptr->DisplayData();
delete b_ptr;
return 0;
}
编译后输出如下
jeff@jeff:~/jeffPro/practice/grammar/c++$ ./main
Base()
Derive()
m_data: hello world
~Base()
jeff@jeff:~/jeffPro/practice/grammar/c++$
可以看到当使用 delete 操作符删除一个指向派生类对象的基类指针时,派生类的析构函数并没有调用从而导致派生类的资源没有得到正确的释放造成内存泄漏。
虚析构函数的主要作用就是解决上述通过基类指针删除派生类对象时产生的内存泄漏问题。 通过在基类中声明一个虚析构函数,确保在多态情况下析构函数的调用是正确的,遵循先调用派生类的析构函数,再调用基类的析构函数的顺序。这样可以保证资源的正确释放。
将基类析构函数声明为虚析构函数后重新编译输出如下
jeff@jeff:~/jeffPro/practice/grammar/c++$ ./main
Base()
Derive()
m_data: hello world
~Derive()
~Base()
jeff@jeff:~/jeffPro/practice/grammar/c++$
可以看到,通过将基类析构函数声明为虚函数可以让编译器在运行时根据实际对象类型来调用相应的析构函数,从而确保所有的资源都能正确地得到释放,避免内存泄漏。
总结
在C++中,如果基类的析构函数没有声明为虚函数,那么在通过基类指针删除派生类对象时,只会调用基类的析构函数。这会导致派生类的析构函数不被调用,从而导致派生类中分配的资源没有得到正确释放,进而引起内存泄漏和其他资源泄漏问题。通过将基类的析构函数声明为虚函数,可以确保正确调用所有相关类的析构函数,安全地释放资源。