6

C++学习之多态-虚析构和纯虚析构

 2 years ago
source link: https://blog.csdn.net/weixin_44618297/article/details/120556165
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

C++学习之多态-虚析构和纯虚析构

不想理你的阿乐 2021-09-29 21:15:04 28
分类专栏: C++ 文章标签: c++
专栏收录该内容
32 篇文章 0 订阅

多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码

解决方式:将父类中的析构函数改为虚析构或者纯虚析构

先看一个案例,子类在堆区开辟了空间:

#include<iostream>
#include<string>
using namespace std;


class animal
{
public:
	animal()
	{
		cout << "animal的构造函数" << endl;
	}

	virtual void speak() = 0;//纯虚函数

	~animal()
	{
		cout << "animal的析构函数" << endl;
	}
	
};

class cat:public animal
{
public:
	cat(string name)  //构造函数
	{
		cout << "cat的构造函数" << endl;
		m_name = new string(name);//在堆区开辟内存
	}


	virtual void speak()//子类中的virtual 加不加都行
	{
		cout <<*m_name<< "小猫在说话" << endl;
	}

	~cat()
	{
		if (m_name != NULL)
		{
			delete m_name;
			m_name = NULL;
		}
		cout << "cat的析构函数" << endl;
	}

public:
	string* m_name;

};

void main()
{
	animal* an = new cat("Tom");
	an->speak();
	delete an;//父类指针析构的时候,不会调用子类的析构,造成内存泄露
}

在这里插入图片描述
按照顺序,创建对象时,父类的构造先调用,之后调用子类的构造;
删除对象时,应该先调用子类的析构,在调用父类的析构;但是现在没有调用子类的析构,而且子类有堆区开辟的空间,这就造成了内存没有释放干净,造成了内存泄露。

解决办法:使用虚析构
#include<iostream>
#include<string>
using namespace std;


class animal
{
public:
	animal()
	{
		cout << "animal的构造函数" << endl;
	}
	virtual void speak() = 0;//纯虚函数
	/*~animal()
	{
		cout << "animal的析构函数" << endl;
	}*/
	virtual~animal()//虚析构:解决了父类对象释放子类内存,这时候就回去调用子类的析构
	{
	    << "animal的析构函数" << endl;
	}	
};

class cat:public animal
{
public:
	cat(string name)  //构造函数
	{
		cout << "cat的构造函数" << endl;
		m_name = new string(name);//在堆区开辟内存
	}
	virtual void speak()//子类中的virtual 加不加都行
	{
		cout <<*m_name<< "小猫在说话" << endl;
	}

	~cat()
	{
		if (m_name != NULL)
		{
			delete m_name;
			m_name = NULL;
		}
		cout << "cat的析构函数" << endl;
	}
public:
	string* m_name;
};

void main()
{
	animal* an = new cat("Tom");
	an->speak();
	delete an;//父类指针析构的时候,不会调用子类的析构,造成内存泄露
}

在这里插入图片描述
在父类的析构函数前加:virtual 就可以了;这时候子类的析构就调用了。

这时也可以使用纯虚析构:
class animal
{
public:
	animal()
	{
		cout << "animal的构造函数" << endl;
	}
	virtual void speak() = 0;//纯虚函数

	/*virtual~animal()//虚析构:解决了父类对象释放子类内存,这时候就回去调用子类的析构
	{
	    << "animal的析构函数" << endl;
	}	*/

   virtual~animal() = 0; //属于抽象类,无法实例化对象
   //纯虚析构,但是纯虚析构不能与纯虚函数一样为空;是必须要写实现的,因为父类中也可能有一些资源需要释放。
};

//可以在类外写纯虚析构的具体实现,那么类内就是声明
animal::~animal()
{
	cout << "animal的纯析构函数" << endl;
}

在这里插入图片描述

虚析构和纯虚析构共性:

  • 可以解决父类指针释放子类对象
  • 都需要有具体的函数实现

虚析构和纯虚析构区别:

  • 如果是纯虚析构,该类属于抽象类,无法实例化对象

虚析构语法:

virtual ~类名(){}

纯虚析构语法:

virtual ~类名() = 0;

类名::~类名(){}

如果子类中没有堆区数据,可以不写虚析构或纯虚析构


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK