[C++核心编程](九):类和对象——多态**

目录

多态的分类

多态的原理剖析

多态的优点

纯虚函数和抽象类

虚析构和纯虚析构


多态是C++面向对象三大特性之一

多态的分类

  • 静态多态

-函数重载运算符重载属于静态多态,复用函数名

-函数地址绑定-编译阶段确定函数地址

  • 动态多态

-派生类虚函数实现运行时多态

-函数地址绑定-运行阶段确定函数地址

动态多态满足条件:

1.继承关系

2.子类要重写(函数返回值类型、函数名、参数列表完全相同)父类的虚函数

动态多态的使用:

父类的指针或者引用 指向 子类的对象

cpp 复制代码
#include <iostream>
#include <string>

using namespace std;

class Animal
{
public:
	//虚函数
	virtual void speak()
	{
		cout << "动物在说话" << endl;
	}
};

class Cat:public Animal
{
public:
	void speak()
	{
		cout << "小猫在说话" << endl;
	}
};

class Dog :public Animal
{
public:
	void speak()
	{
		cout << "小狗在说话" << endl;
	}
};

//地址早绑定-编译阶段确定函数地址
//如果想执行让猫说话,就要进行晚绑定,使用虚函数
void dospeak(Animal& animal)
{
	animal.speak();
}

void test(void)
{
	Cat cat;
	dospeak(cat);

	Dog dog;
	dospeak(dog);
}

int main(void)
{
	test();
	return 0;
}

多态的原理剖析

父类内部结构vfptr-虚函数(表)指针 指向 vftable(表内记录虚函数的地址)

当子类重写父类的虚函数:子类中的虚函数表内部会替换成子类的虚函数地址

当父类的指针或者引用指向子类对象时,发生多态。

多态的优点

  • 代码组织结构清晰
  • 可读性强
  • 利于前期和后期的扩展和维护
  • (开闭原则)
cpp 复制代码
#include <iostream>
#include <string>

using namespace std;
//举例实现一个简易的计算器
class AbstractCalulator
{
public:
	//虚函数
	virtual int getResult()
	{
		return 0;
	}
	int n_number;
	int m_number;
};

class AddCalculator :public AbstractCalulator
{
public:
	int getResult()
	{
		return n_number + m_number;
	}
};

class SubCalculator :public AbstractCalulator
{
public:
	int getResult()
	{
		return n_number - m_number;
	}
};

class MulCalculator :public AbstractCalulator
{
public:
	int getResult()
	{
		return n_number * m_number;
	}
};

void test(void)
{
	AbstractCalulator* abc = new AddCalculator;
	abc->n_number = 10;
	abc->m_number = 10;

	cout << abc->n_number << "+" << abc->m_number << "=" << abc->getResult() << endl;
	delete abc;

	abc = new SubCalculator;
	abc->n_number = 10;
	abc->m_number = 10;

	cout << abc->n_number << "-" << abc->m_number << "=" << abc->getResult() << endl;
	delete abc;

	abc = new MulCalculator;
	abc->n_number = 10;
	abc->m_number = 10;

	cout << abc->n_number << "*" << abc->m_number << "=" << abc->getResult() << endl;
	delete abc;
}

int main(void)
{
	test();
	return 0;
}

纯虚函数和抽象类

在多态中,通常父类中虚函数的实现是毫无意义的,主要是调用子类重写的内容,因此可以将虚函数改为纯虚函数。

纯虚函数语法:virtual 返回值类型 函数名 (参数列表) = 0;

当类中有了纯虚函数,这个类被称为 抽象类

抽象类特点:

  • 无法实例化对象
  • 子类必须重写抽象类中的纯虚函数,否则也属于抽象类
cpp 复制代码
#include <iostream>
#include <string>

using namespace std;

class Base
{
public:
	virtual void func() = 0;

};

class Son:public Base
{
public:
	void func()
	{
		cout << "Son 's func()" << endl;
	}
};

void test(void)
{
	//Base base; 抽象类无法实例化对象
	//new Base;  抽象类无法实例化对象

	Base * base = new Son;
	base->func();
}

int main(void)
{
	test();
	return 0;
}

虚析构和纯虚析构

如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码导致内存泄漏 ,解决办法是将父类的析构函数改为虚析构 或者纯虚析构;

虚析构和纯虚析构的共性

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

虚析构和纯虚析构的区别

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

虚析构语法:virtual ~类名(){}

纯虚析构语法:virtual ~类名() = 0; 类名::~类名(){}

cpp 复制代码
#include <iostream>
#include <string>

using namespace std;

class AbstractAnimal
{
public:
	AbstractAnimal()
	{
		cout << "AbstractAnimal 构造函数调用" << endl;
	}
	//virtual ~AbstractAnimal()
	//{
	//	cout << "AbstractAnimal 析构函数调用" << endl;
	//}
	virtual ~AbstractAnimal() = 0;
	virtual void speak() = 0;
};

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

class Dog :public AbstractAnimal
{
public:
	Dog(string name)
	{
		cout << "Dog 构造函数调用" << endl;
		m_name = new string(name);
	}
	~Dog()
	{
		if (m_name != NULL)
		{
			cout << "Dog 析构函数调用" << endl;
			delete m_name;
			m_name = NULL;
		}
	}
	void speak()
	{
		cout << *m_name << "  Dog speaking" << endl;
	}
	string* m_name;
};

void test(void)
{
	AbstractAnimal* abs = new Dog("Tom");
	abs->speak();
	delete abs;
}

int main(void)
{
	test();
	return 0;
}

推荐文章:C++核心编程(八):类和对象------继承**

相关推荐
leisoo80971 小时前
100GBA股股票数据怎么存ClickHouseRedisMySQLJSON完整对比
大数据·linux·服务器·开发语言·python
不会代码的小猴2 小时前
21. 泛型编程上
开发语言·c++·笔记·算法
青瓦梦滋2 小时前
传输层UDP/TCP协议
linux·网络·c++·网络协议·tcp/ip·udp
一只旭宝3 小时前
细讲C加加【9】C++ std::function与std::bind详解|仿函数、绑定器、类成员绑定、占位符、成员偏移指针
开发语言·c++·算法
coder!mq5 小时前
说几个常见的语法糖?
java·开发语言·算法
gugucoding5 小时前
38. 【Java】Stream API(下):高级操作与性能
java·开发语言
Lhan.zzZ5 小时前
在 Visual Studio 2022 中打造可扩展的动态链接库模块:从零搭建到原理解析
开发语言·c++·visual studio
心平气和量大福大5 小时前
android-实例-蒲公英-更新与安装-5-签名与生成APK
android·java·开发语言
码哥DFS5 小时前
构造函数、实例对象、对象原型 ----三者关系
开发语言·javascript·原型模式
quantdash_cc6 小时前
告别自建 Requests/BS4 网页爬虫:基于 QuantDash 搭建零维保的高性能量化行情流水线
开发语言·爬虫·python·pandas·量化·quantdash