C++基类接口设计之虚析构函数

1. 问题描述:
最近,在通过使用抽象类作为接口时出现了内存泄漏的问题。通过阅读相关文章,发现是因为在构建时基类析构函数没有设置为虚函数。
2. 相关概念:
(1)虚函数: 某基类中声明为virtual并在一个或多个派生类中重新定义的成员函数叫做虚函数。

virtual void fun();

(2)纯虚函数: 将其声明为如下形式的成员函数为纯虚函数,没有实现。

virtual void fun() = 0;

(3)抽象类: 有一个成员函数是纯虚函数的类——抽象类不能实例化。

class Father0
{
public:
	virtual ~Father0(){}
	virtual void fun() = 0;
};

3. 虚函数实现多态
在定义了虚函数后,可实现在派生类中对虚函数进行重写,从而实现统一的接口和不同的执行过程。在函数运行阶段动态的选择合适的成员函数。
相关的实现代码如下:

#include 
using namespace std;
class Father0
{
public:
	virtual ~Father0(){}
	virtual void fun() = 0;
};
class Father: public Father0
{
public:
	Father() 
	{
		cout << "class Father init" << endl;
	}
	virtual ~Father() 
	{
		cout << "class Father destroyed" << endl;
	}
	void fun0()
	{
		cout << "this is a base function" << endl;
	}
	virtual void fun()
	{
		cout << "this is a virtual function" << endl;
	}
};
class Son1 : public Father 
{
public:
	Son1() 
	{
		cout << "class Son1 init" << endl;
	}
	~Son1() 
	{
		cout << "class Son1 destroyed" << endl;
	}
	void fun()
	{
		cout << "this is a virtual function of Son1" << endl;	
	}
};
class Son2 : public Son1 
{
public:
	Son2()
	{
		cout << "class Son2 init" << endl;
	}
	~Son2() 
	{
		cout << "class Son2 destroyed" << endl;
	}
	void fun11()
	{
		cout << "this is a virtual function of Son2" << endl;
	}
};
int main() 
{
	Father0* p;
	p= new Son2;
	p->fun();
	delete p;
	system("pause");
	return 0;
}

构建抽象类Father0,通过Father0的指针指向子类,当指向不同的子类时可以实现不同的功能(多态性)。
当使用抽象类指针指向子类Son2时,构造函数从父类开始,析构函数相反。另外,在多重继承时,如果所指向的子类没有要调用的函数,则往上一层进行查找并调用。如下所示为运行的结果:

/*
class Father init
class Son1 init
class Son2 init
this is a virtual function of Son1
class Son2 destroyed
class Son1 destroyed
class Father destroyed
*/

当不将抽象类的析构函数设为虚函数时,析构时只有指针类会释放。在以上代码中,若将Father0类的析构函数的virtual取消,则产生如下运行结果:

/*
class Father init
class Son1 init
class Son2 init
this is a virtual function of Son1
*/

另外,若将Father0类的析构函数的virtual取消,Father类的析构函数设为虚函数,将指针更改为Father则产生如下运行结果:

/*
class Father init
class Son1 init
class Son2 init
this is a virtual function of Son1
class Father destroyed
*/

若仅仅将指针更改为Father,则产生如下运行结果:

/*
class Father init
class Son1 init
class Son2 init
this is a virtual function of Son1
class Son2 destroyed
class Son1 destroyed
class Father destroyed
*/

4. 结论
在通过构建虚函数实现多态时,一定要记得将基类的析构函数设为虚函数。另外,若不使用基类指针,则不需要将基类的析构函数设为虚函数。
如将

Father0* p;
p= new Son2;

改为

Son2* p;
p= new Son2;

则运行结果为:

/*
class Father init
class Son1 init
class Son2 init
this is a virtual function of Son1
class Son2 destroyed
class Son1 destroyed
class Father destroyed
*/

最后,对析构函数感兴趣的朋友可以查看下面的参考文献。

参考文献:
[1] 为什么析构函数必须是虚函数
[2] 虚函数与多态
[3] c++虚函数详解

你可能感兴趣的:(C++学习,c++,开发语言)