11—C++类和对象—多态

37类—多态(多态的基本概念)

#include<iostream>
using namespace std;
#include<string>
//多态的基本概念
/*
多态是C++面向对象三大特性之一

多态分为两类
静态多态: 函数重载 和 运算符重载属于静态多态,复用函数名
动态多态: 派生类和虚函数实现运行时多态

静态多态和动态多态区别:
静态多态的函数地址早绑定,编译阶段确定函数地址
动态多态的函数地址晚绑定,运行阶段确定函数地址

动态多态满足条件:
1、有继承关系
2、子类重写父类中的虚函数

函数重写的条件:除了函数体,其它的都一样

动态多态使用:
父类指针或引用指向子类对象
*/

//动物类
class Animal
{
public:
	//为了实现地址晚绑定,要在基类的函数之前添加关键字virtual,虚函数
	virtual void speak()
	{
		cout << "动物会叫" << endl;
	}
};
//猫类
class Cat:public Animal
{
public:
	void speak()
	{
		cout << "小猫喵喵叫" << endl;
	}
};

//我们希望传入什么对象,那么就调用什么对象的函数
//地址早绑定,在编译阶段确定函数的地址
//如果想执行让猫说话,那么这个函数地址就不能提前绑定,需要在编译阶段进行绑定,地址晚绑定
void doSpeak(Animal & animal)//Animal &animal=cat;
{
	animal.speak();
}

void Test01()
{
	Cat cat01;
	doSpeak(cat01);
}
int main()
{
	Test01();
	system("pause");
	return 0;
}

38类—多态(多态的原理剖析)

#include<iostream>
using namespace std;
#include<string>
//多态的原理剖析
/*
先定义一个Animal01类,然后查看在成员函数前不加virtual关键字时,所占用的空间大小?
由于类的成员变量和成员函数是分看存储的,所以占用的字节为1(空类占用1个字节)

在定义一个Animal02类,然后查看在成员函数前加virtual关键字时,所占用的空间大小?
因为里面有一个虚函数指针(占用四个字节)


*/
class Animal01{
public:
	void speak(){
		cout << "动物会叫" << endl;
	}
};

class Animal02{
public:
	virtual void speak(){
		cout << "动物会叫" << endl;
	}
};

class Cat :public Animal02{
public:
	//重写(覆盖)父类中的speak方法
	virtual void speak(){
		cout << "小猫喵喵叫" << endl;
	}

};

void Test01(){
	cout << "不带虚关键字的Animal类占用字节数:"<<sizeof(Animal01) << endl;
	cout << "带虚关键字的Animal类占用字节数:" << sizeof(Animal02) << endl;
}

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

39类—多态(体验多态带来的便捷)

#include<iostream>
using namespace std;
#include<string>
/*
虽然看似代码量增加了但是它好呀!!!!!
多态的优点:
1.代码组织结构清晰
2.可读性强
3.利于前期和后期的扩展以及维护

小感慨:
由于多态的这种特点,才显得面向接口编程有多么方便,接口类写好,扩充功能直接追加就好了,真棒

在程序设计中我们提倡开闭原则:对扩展进行开发,对修改进行关闭
*/

//定义一个计算器的类Calculater01,计算器有加减乘除的功能:不用多态
class Calculater01{
public:
	int getResult(string oper)
	{
		if (oper == "+")
		{
			return m_Num1 + m_Num2;
		}
		else if (oper == "-")
		{
			return m_Num1 - m_Num2;
		}
		else if (oper == "*")
		{
			return m_Num1 * m_Num2;
		}
		//如果要增加一个除法运算,就要修改源码(不方便)
		/*
		在程序设计中我们提倡开闭原则:对扩展进行开发,对修改进行关闭
		*/
	}
public:
	int m_Num1;
	int m_Num2;
};
void Test01(){
	Calculater01 c1;
	c1.m_Num1 = 10;
	c1.m_Num2 = 10;
	cout << c1.m_Num1 << "+" << c1.m_Num2 << "=" << c1.getResult("+") << endl;
	cout << c1.m_Num1 << "-" << c1.m_Num2 << "=" << c1.getResult("-") << endl;
	cout << c1.m_Num1 << "*" << c1.m_Num2 << "=" << c1.getResult("*") << endl;
}


//定义一个计算器的类Calculater02,计算器有加减乘除的功能:使用多态
class Calculater02{
public:
	virtual int getResult(){
		return 0;
	}
public:
	int m_Num1;
	int m_Num2;
};
//定义一个加法的子类
class Add:public Calculater02{
	//重写父类中的方法
	virtual int getResult()
	{
		return m_Num1 + m_Num2;
	}
	//如果想加一个减法的功能,只需要在创建一个子类即可
};
class Subtract:public Calculater02{
	//重写父类中的方法
	virtual int getResult()
	{
		return m_Num1 - m_Num2;
	}
};
class  Multiply :public Calculater02{
	//重写父类中的方法
	virtual int getResult()
	{
		return m_Num1 * m_Num2;
	}
};

void Test02(){
	//多态:父类的指针指向子类对象
	Calculater02 *c2 = new Add;
	c2->m_Num1 = 10;
	c2->m_Num2 = 10;
	cout << c2->m_Num1 << "+" << c2->m_Num2 << "=" << c2->getResult() << endl;
	//堆区数据手动开辟手动释放
	//用完后记得销毁(只是删除了堆区的数据:new出来的东西)
	delete c2;
	
	c2 = new Subtract;
	c2->m_Num1 = 10;
	c2->m_Num2 = 10;
	cout << c2->m_Num1 << "-" << c2->m_Num2 << "=" << c2->getResult() << endl;
	delete c2;
	
	c2 = new Multiply;
	c2->m_Num1 = 10;
	c2->m_Num2 = 10;
	cout << c2->m_Num1 << "*" << c2->m_Num2 << "=" << c2->getResult() << endl;
	delete c2;
}
int main(){
	Test01();
	Test02();
	system("pause");
	return 0;
}

40类—多态(纯虚函数和抽象类)

#include<iostream>
using namespace std;
#include<string>
/*
在多态中,通常父类中虚函数的实现是毫无意义的,主要都是调用子类重写的内容
因此可以将虚函数改为纯虚函数

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

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

抽象类特点:
无法实例化对象
子类必须重写抽象类中的纯虚函数,否则也属于抽象类
*/

class Base
{
public:
	//类中只要有一个纯虚函数就称为抽象类
	//抽象类无法实例化对象
	//子类必须重写父类中的纯虚函数,否则也属于抽象类
	virtual void func() = 0;
};

class Son :public Base
{
public:
	virtual void func()
	{
		cout << "func调用" << endl;
	};
};

void Test01()
{
	//多态:父类指针指向子类对象
	Base * base = NULL;
	//base = new Base; // 错误,抽象类无法实例化对象
	base = new Son;
	base->func();
	delete base;//记得销毁
}

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

41类—多态(虚析构和纯析构)

#include<iostream>
using namespace std;
#include<string>
//虚析构和纯虚析构
/*
多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码
解决方式:将父类中的析构函数改为虚析构或者纯虚析构

虚析构和纯虚析构共性:
1.可以解决父类指针释放子类对象
2.都需要有具体的函数实现

虚析构和纯虚析构区别:
1.如果是纯虚析构,该类属于抽象类,无法实例化对象

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

纯虚析构语法(需要声明,也需要实现):
virtual ~类名() = 0;

类名::~类名(){}

总结:
​	1. 虚析构或纯虚析构就是用来解决通过父类指针释放子类对象
​	2. 如果子类中没有堆区数据,可以不写为虚析构或纯虚析构
​	3. 拥有纯虚析构函数的类也属于抽象类
*/
class Animal{
public:
	Animal(){
		cout << "动物的构造函数执行了" << endl;
	}

	//父类只用这样的析构,父类指针在释放时无法调用到子类的析构代码
	/*
	~Animal(){
		cout << "动物的析构函数执行了" << endl;
	}
	*/

	//把父类的析构函数改为纯析构或者虚析构
	//virtual ~Animal(){cout << "动物的析构函数执行了" << endl;}//虚析构
	
	virtual ~Animal()= 0;//纯虚析构(声明)

	//纯虚函数
	virtual void speak() = 0;
};
//纯虚析构实现(还是虚析构好写点,以后用虚析构)
Animal::~Animal(){cout << "动物的析构函数执行了" << endl;}

class Cat :public Animal
{
public:
	Cat(string name)
	{
		cout << "小猫的构造函数执行了" << endl;
		//new出来的必须用指针来接收,因为返回的是地址
		m_Name=new string(name);
	}
	~Cat()
	{
		cout << "小猫的析构函数执行了"<<endl;
		if (m_Name!=NULL)
		{
			delete m_Name;
			m_Name = NULL;//避免野指针(因为释放的是堆区数据,指针依然在,让他指向空)
		}
	}
	//父类中的纯虚函数子类必须要重写
	virtual void speak()
	{
		cout <<*m_Name << "小猫喵喵叫" << endl;
	}
	string  *m_Name;
};
void Test01()
{
	Animal *animal = new Cat("Tom");
	animal->speak();
	delete animal;
}
int main(){
	Test01();
	system("pause");
	return 0;
}

42类—多态(案例)

#include<iostream>
#include<string>
using namespace std;
/*
本事例为一个电脑组装的案例:
一台电脑包括:内存卡(CPU),显卡(Video card),存储器(memory)

使用多态之后无论以后要创建多少台电脑,只要零件厂家不变,就不需要修改源码

如果不用多态,组装电脑的类就要写多个,因为零件生产厂家不一样,
使用哪一家的零件就要为这种零件组成创建一个电脑组装的类
*/

//创建零件的虚基类(因为要使用多态)(还可以使用虚析构)
class CPU
{
public:
	virtual void calculate() = 0;
};
class VideoCard
{ 
public:
	virtual void display() = 0; 
};
class Memory
{ 
public:
	virtual void storage() = 0;
};

//创建具体生产零件的厂商(intel)
class IntelCPU :public CPU
{
public:
	virtual void calculate()
	{
		cout << "IntelCPU开始工作了" << endl;
	}
};

class IntelVideoCard :public VideoCard
{
public:
	virtual void display()
	{
		cout << "IntelVideoCard开始工作了" << endl;
	}
};

class IntelMemory :public Memory
{
public:
	virtual void storage()
	{
		cout << "IntelMemory开始工作了" << endl;
	}
};

//创建具体生产零件的厂商(AISMALL)
class AISMALLCPU :public CPU
{
public:
	virtual void calculate()
	{
		cout << "AISMALLCPU开始工作了" << endl;
	}
};

class AISMALLVideoCard :public VideoCard
{
public:
	virtual void display()
	{
		cout << "AISMALLVideoCard开始工作了" << endl;
	}
};

class AISMALLMemory :public Memory
{
public:
	virtual void storage()
	{
		cout << "AISMALLMemory开始工作了" << endl;
	}
};

//组装电脑类
class Computer{
public:
	//创建构造函数(注意形式参数的类型,都为类类型,而且是使用指针接收)
	//如果不用多态也就不能使用基类类型接收数据,这样换个零件就要重写这个构造
	Computer(CPU *cpu, VideoCard * videoCard, Memory *memory)
	{
		m_cpu = cpu;
		m_videoCard = videoCard;
		m_memory = memory;
	}
	void doWork()
	{
		m_cpu->calculate();
		m_videoCard->display();
		m_memory->storage();
	}
	//提供析构函数,释放3个电脑零件(开辟到堆区的数据手动释放)
	~Computer()
	{
		if (m_cpu != NULL)
		{
			delete m_cpu;
			m_cpu = NULL;
		}
		if (m_videoCard != NULL)
		{
			delete m_videoCard;
			m_videoCard = NULL;
		}
		if (m_memory != NULL)
		{
			delete m_memory;
			m_memory = NULL;
		}
	}
	//创建成员变量(使用指针,将内存开辟到堆区)
private:
	CPU *m_cpu;
	VideoCard *m_videoCard;
	Memory *m_memory;
};

//组装电脑
void Test01()
{
	//使用多态创建电脑的零件
	CPU *intelCPU = new IntelCPU;
	VideoCard *intelVideoCard = new IntelVideoCard;
	Memory *intelmemory = new IntelMemory;

	CPU *aismallCPU = new AISMALLCPU;
	VideoCard *aismallVideoCard = new AISMALLVideoCard;
	Memory *aismallmemory = new AISMALLMemory;
	
	//组装第一台电脑
	Computer *computer1 = new Computer(intelCPU, intelVideoCard, intelmemory);
	//让第一台电脑工作
	computer1->doWork();
	cout << "----------------------" << endl;
	//组装第二台电脑
	Computer *computer2 = new Computer(aismallCPU, aismallVideoCard, aismallmemory);
	computer2->doWork();
	cout << "----------------------" << endl;
	//创建第三台电脑
	Computer *computer3 = new Computer(intelCPU, aismallVideoCard, intelmemory);
	computer3->doWork();

}
int main(){
	Test01();
	system("pause");
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

彤彤的小跟班

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值