c++ 多态 学习总结3 虚析构和纯虚析构

为什么要用虚析构和纯虚析构:

在使用多态时,如果子类中有属性开辟到堆区,那么我们在释放(或delete)父类的指针时无法调用子类的析构代码,释放子类在堆区的内存,会导致内存泄漏的问题。

eg:

#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)
	{
		this->m_name = new string(name);
		cout << "这是Cat类的构造函数的调用" << endl;
	}
	virtual void speak()
	{
		cout <<*m_name<< "在叫" << endl;
	}
	~Cat()
	{
		if (this->m_name != NULL)
		{
			cout << "这是Cat类的析构函数调用" << endl;
			delete m_name;
			m_name = NULL;
		}
	}
private:
	string* m_name;
};

int main()
{
	Animal* a = new Cat("加菲猫");
	a->speak();
	delete a;
}

运行结果:

可以看到虽然Cat类中的m_name是存储在堆区的数据,但我们无法通过释放父类的指针调用子类的析构函数释放子类在堆区的内存。 

解决方法:

将父类的析构函数变为虚析构或纯虚析构

虚析构和纯虚析构的共同点:

1.都可以解决释放父类指针时无法调用子类析构代码的问题。

2.二者都需要具体的函数实现。

虚析构和纯虚析构的不同点:

虚析构时可以正常实例化父类和子类的对象,但是纯虚析构会使父类变为抽象类,导致父类和子类都无法实例化对象。

虚析构的语法:

virtual ~类名(){}

纯虚析构的语法:

1.virtual ~类名()=0;

2.类名::~类名(){}

ps:虽然纯虚析构在类内直接=0;但依旧需要在类外实现,即类内声明,类外实现。

因为我们不知道父类是否有属性开辟到堆区,我们依旧需要父类有一个有具体实现的析构函数。

这点与纯虚函数不同!

上面代码使用虚析构后:

#include <iostream>
#include <string>
using namespace std;
class Animal
{
public:
	Animal()
	{
		cout << "这是Animal类的构造函数调用" << endl;
	}
	virtual void speak() = 0;
	virtual ~Animal()
	{
		cout << "这是Animal类的虚析构函数调用" << endl;
	}
};



class Cat:public Animal
{
public:
	Cat(string name)
	{
		this->m_name = new string(name);
		cout << "这是Cat类的构造函数的调用" << endl;
	}
	virtual void speak()
	{
		cout <<*m_name<< "在叫" << endl;
	}
	virtual ~Cat()
	{
		if (this->m_name != NULL)
		{
			cout << "这是Cat类的析构函数调用" << endl;
			delete m_name;
			m_name = NULL;
		}
	}
private:
	string* m_name;
};

int main()
{
	Animal* a = new Cat("加菲猫");
	a->speak();
	delete a;
}

运行结果:

 

可以看到Cat类的析构函数被成功调用的同时Animal类的虚构函数的实现也是正常进行的。

 上面代码使用纯虚析构后:

#include <iostream>
#include <string>
using namespace std;
class Animal
{
public:
	Animal()
	{
		cout << "这是Animal类的构造函数调用" << endl;
	}
	virtual void speak() = 0;
	virtual ~Animal() = 0;
};

Animal:: ~Animal()
{
	cout << "这是Animal类的纯虚析构函数调用" << endl;
}

class Cat:public Animal
{
public:
	Cat(string name)
	{
		this->m_name = new string(name);
		cout << "这是Cat类的构造函数的调用" << endl;
	}
	virtual void speak()
	{
		cout <<*m_name<< "在叫" << endl;
	}
	virtual ~Cat()
	{
		if (this->m_name != NULL)
		{
			cout << "这是Cat类的析构函数调用" << endl;
			delete m_name;
			m_name = NULL;
		}
	}
private:
	string* m_name;
};

int main()
{
	Animal* a = new Cat("加菲猫");
	a->speak();
	delete a;
}

运行结果:

 

我认为主要要注意的地方是 区分纯虚函数和纯虚函数的不同:

纯虚函数不需要具体实现,只需要类中声明。

纯虚函数是需要具体实现的,只不过是在类外实现的。

并且二者都会使父类变为抽象类

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值