虚析构函数

在看《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类的析构函数。这样就不会出现由于析构函数未被调用而导致的内存泄漏。

posted @ 2019-06-27 08:57  尚修能的技术博客  阅读(332)  评论(0编辑  收藏  举报