在看《Essential C++》的时候,碰到一句话,不是很明白,今天在看《程序员面试宝典》的时候,又看到了这个问题,记录下来。
《Essential C++》中写到
根据一般规则,凡基类定义有一个(或多个)虚函数,应该要将其析构函数声明为virtual
看下面的代码
#include "pch.h"
#include <iostream>
using namespace std;
class CBase
{
public:
~CBase()
{
}
};
class CChild : public CBase
{
public:
~CChild()
{
}
};
int main()
{
CChild c;
return 0;
}
上面代码在运行时,由于在生成CChlid对象c时,实际上在调用CChild类的构造函数之前必须首先调用其基类CBase的构造函数,所以当撤销c时,也会在调用CChild类析构函数之后,调用CBase类的析构函数(析构函数调用顺序和构造函数相反)。也就是说,无论析构函数是不是虚析构函数,派生类对象被撤销时,肯定会依次调用其基类的析构函数。
那么为什么需要虚析构函数那?
因为多态的存在!
int main()
{
CChild c;
CBase* pBase;
pBase = &c;
return 0;
}
考虑上面的代码,在pBase指针被撤销时,调用的是CBase的析构函数还是CChild的析构函数那?显然是CBase的(静态联编)析构函数,但如果把CBase类的析构函数改为virtual型,当pBase指针被撤销时,就会先调用CChild类析构函数,再调用CBase类的析构函数。
看下面的两份代码
#include "pch.h"
#include <iostream>
using namespace std;
class CBase
{
public:
~CBase()
{
cout << "这是CBase类的析构函数" << endl;
}
};
class CChild : public CBase
{
public:
~CChild()
{
cout << "这是CChild类的析构函数" << endl;
}
};
int main()
{
//CChild c;
CBase* pBase;
pBase = new CChild();
delete pBase;
return 0;
}
当pBase被撤销时,因为CBase类的析构函数不是虚函数,non-vitrual函数在编译时便已完成解析,根据该对象被调用时的类型来判断,所以只会调用CBase类自己的析构函数。从而不会释放CChild占据的内存,造成内存泄漏。
再看这份代码
#include "pch.h"
#include <iostream>
using namespace std;
class CBase
{
public:
virtual ~CBase()
{
cout << "这是CBase类的析构函数" << endl;
}
};
class CChild : public CBase
{
public:
~CChild()
{
cout << "这是CChild类的析构函数" << endl;
}
};
int main()
{
//CChild c;
CBase* pBase;
pBase = new CChild();
delete pBase;
return 0;
}
由于CBase类的析构函数是虚函数,当pBase指针被撤销时,就会先调用CChild类的析构函数,再调用CBase类的析构函数。这样就不会出现由于析构函数未被调用而导致的内存泄漏。