C++入门学习:虚析构和纯虚析构*

当存在父类 Animal  子类 Cat

Animal* animal = new Cat("Tom");
animal->speak();
delete animal;

使用父类指针  指向在堆区上  创建的子类对象  此时animal的静态类型是Animal*  动态类型是 Cat*  speak是虚函数  即speak函数的调用类型在运行时确定  可以调用Cat类中的speak函数  

但在释放内存时  Cat类的析构函数却不会被调用

~Cat()
{
	if (m_Name != NULL) 
	{
		cout << "Cat 析构函数调用" << endl;
		delete m_Name;;
		m_Name = NULL;
	}
}

要解决这个问题(父类指针无法完全释放子类对象) 可以利用虚析构

逻辑详解:没有虚析构时  函数地址会在编译阶段直接绑定父类的析构函数  运行时只调用父类的析构函数  使用虚析构后  该析构函数及其派生类中的析构函数会存储到虚函数表中  按照编译器自动调用析构函数的顺序  先调用实际对象(派生类)的析构函数  再调用基类析构函数  从而避免内存泄漏

实现方法 

1)虚函数  父类中的析构函数添加virtual关键字

virtual ~Animal()
{
	cout << "Animal 虚析构函数调用" << endl;
} 

2)纯虚函数  父类中声明纯虚函数

virtual ~Animal() = 0; 

在类外提供实现

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

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

纯虚析构  需要声明  也需要实现
有了纯虚析构后  这个类也属于抽象类  无法实例化对象


代码示例

#include <string>
#include <iostream>
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)
	{
		cout << "Cat 构造函数调用" << endl;
		m_Name = new string(name);
	}
	virtual void speak()
	{
		cout << *m_Name << "小猫在说话" << endl;
	}
	~Cat()
	{
		if (m_Name != NULL) 
		{
			cout << "Cat 析构函数调用" << endl;
			delete m_Name;;
			m_Name = NULL;
		}
	}

	string *m_Name;
};

//测试函数
void test01()
{
	Animal* animal = new Cat("Tom");
	animal->speak();
	//父类指针在析构时  不会调用子类中的析构函数  导致子类中如果存在堆区属性  出现内存泄漏
	delete animal;
}


int main()
{
	test01();
	system("pause");
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值