(C++学习笔记九)多态

十一. 多态

1.Code :

#include<iostream>
using namespace std;

//  多态 !
// 多态分为两类:
// 静态多态 : 函数重载 和 运算符重载 属于多态,复用函数名
// 动态多态 : 派生类 和 虚函数实现运行时多态
// 两者的区别:
//          1. 静态多态的函数地址早绑定,编译阶段确定函数地址
//          2. 动态多态.............,运行阶段..........

class qw
{
public:

	// 函数前面加 virtual 关键字,
	//func变为虚函数,那么编译器在编译器的时候就不能确定函数调用
	virtual void func()
	{
		cout << "qw virtual void func();" << endl;
	}
};


class cat :public qw
{
public:
	void func()
	{
		cout << "cat void func();" << endl;
	}
};

class cat1 :public qw
{
public:
	void func()
	{
		cout << "cat1 void func();" << endl;
	}
};

//我们希望传入什么对象,那么就调用什么对象的函数
//如果函数地址在编译阶段就能确定,那么静态联编
//如果函数地址在运行阶段才能确定,就是动态联编
void test(qw& qw1)
{
	qw1.func();
}

//多态满足条件: 
//1、有继承关系
//2、子类重写父类中的虚函数(子类函数名,形参,返回值均与父类相同,但不是虚类)
//多态使用:
//父类指针或引用指向子类对象
void test1()
{
	cat c1;
	test(c1);

	cat1 c2;
	test(c2);
}


//  二, 多态案例一: 计算器类

//普通实现
class Calculator {
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()
{
	//普通实现测试
	Calculator c;
	c.m_Num1 = 10;
	c.m_Num2 = 10;
	cout << c.m_Num1 << " + " << c.m_Num2 << " = " << c.getResult("+") << endl;

	cout << c.m_Num1 << " - " << c.m_Num2 << " = " << c.getResult("-") << endl;

	cout << c.m_Num1 << " * " << c.m_Num2 << " = " << c.getResult("*") << endl;
}

// 抽象类
class Calculator1
{
public:
	virtual int Operation()
	{
		return 0;
	}

	int num1;
	int num2;
};

//加法计算器  Addition calculator
class AddCalculator1:public Calculator1
{
public:
	int Operation()
	{
		return num1 + num2;
	}
};

//减法计算器  Subtract the calculator
class SubCalculator1 :public Calculator1
{
public:
	int Operation()
	{
		return num1 - num2;
	}
};

//乘法计算器  Multiplication calculator
class MulCalculator1 :public Calculator1
{
public:
	int Operation()
	{
		return num1 * num2;
	}
};

void test2()
{
	//加法

	//多态使用条件: 父类指针或引用指向子类对象
	Calculator1* as = new AddCalculator1;
	//指针指向子类对象: AddCalculator1
	//指针类型为 Calculator1 类 
	as->num1 = 10;
	as->num2 = 10;
	cout << as->num1 << " + " << as->num2 << " = " << as->Operation() << endl;
	delete as;
	//开辟堆区后记得销毁

	//减法
	as = new SubCalculator1;
	as->num1 = 10;
	as->num2 = 10;
	cout << as->num1 << " - " << as->num2 << " = " << as->Operation() << endl;
	delete as;

	//加法
	as = new MulCalculator1;
	as->num1 = 10;
	as->num2 = 10;
	cout << as->num1 << " X " << as->num2 << " = " << as->Operation() << endl;
	delete as;
}	


//   三.纯虚函数和抽象类
// 1. 纯虚函数:
//前提: 因为多态中通常父类虚函数实现是毫无意义的,主要调用子类重写的内容.
//     因此将虚函数改为纯虚函数.
//语法: virtual 返回值类型 函数名 (参数列表) = 0;

// 2. 抽象类:
// 当类中有了纯虚函数,这个类也称为: 抽象类
// 特点: 无法实例化对象
//       子类必须重写抽象类中的纯虚函数,否则也属于 抽象类

//    三. 多态案例二: 制饮料

class MakeDrink
{
public:
	virtual void BoilWater() = 0;	//烧水
	virtual void PourCup() = 0;//倒入杯中
	virtual void PutSomething() = 0;//加入�����料

	void MakeSteps()//规定流程
	{
		BoilWater();
		PourCup();
		PutSomething();
	}
};

class M_Tea :public MakeDrink
{
public:
	virtual void BoilWater() 
	{
		cout << "烧水 " << endl;
	}
	virtual void PourCup()
	{
		cout << "倒入茶叶和水 " << endl;
	}
	virtual void PutSomething()
	{
		cout << "加入牛奶 " << endl << endl;
	}
};

class M_Coffee :public MakeDrink
{
public:
	virtual void BoilWater()
	{
		cout << "烧水 " << endl;
	}
	virtual void PourCup()
	{
		cout << "倒入咖啡和水 " << endl;
	}
	virtual void PutSomething()
	{
		cout << "加入?? " << endl << endl;
	}
};


//我们希望传入什么对象,那么就调用什么对象的函数
//如果函数地址在编译阶段就能确定,那么静态联编
//如果函数地址在运行阶段才能确定,就是动态联编

//多态调用的条件: 使用父类指针/引用子类对象

void Func(MakeDrink& qw1)//父类引用子类对象
{
	qw1.MakeSteps();
}

void Func1(MakeDrink* dr)//父类指针指向子类
{
	dr->MakeSteps();
	delete dr;
}

void test3()
{
	cout << " 父类引用子类对象 " << endl;

	M_Tea M_T1;
	M_Coffee M_C1;

	Func(M_T1);
	Func(M_C1);

	cout << " 父类指针指向子类 " << endl;

	Func1(new M_Tea);
	Func1(new M_Coffee);
}


//   四.虚析构 和 纯虚析构
//前提: 多态使用时如果有子类属性开辟到 堆区 ,
//        那么父类指针在释放时无法调用到 子类的析构代码.
//        简言之,就是父类指针无法将子类对象释放干净
//解决方式:将父类中的析构函数改为虚析构或者纯虚析构

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

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

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


//总结:
//​ 1. 虚析构或纯虚析构就是用来解决通过父类指针释放子类对象
//​ 2. 如果子类中没有堆区数据,可以不写为虚析构或纯虚析构
// 3. 拥有纯虚析构函数的类也属于抽象类

class sd
{
public:
	sd()
	{
		cout << "sd 构造函数调用" << endl;
	}

	//~sd()           // Optimization level : 1
	//{
	//	cout << "sd 析构函数调用" << endl;
	//}

	//virtual ~sd()    // Optimization level : 2.0
	//{
	//	cout << "sd 虚析构函数调用" << endl;
	//}

	virtual ~sd() = 0;   // Optimization level : 2.1
	//纯虚析构函数
};

sd::~sd()//再重写? 纯虚析构函数
{
	cout << "sd 纯虚析构函数" << endl;
}

class er:public sd
{
public:
	er(int age)
	{
		cout << "er 构造函数调用" << endl;
		re = new int(age);
		//将 age 开辟到堆区
		//并在析构函数中释放
	}

	~er()
	{
		cout << "er 析构函数调用" << endl;
		if (re != NULL)
		{
			delete re;
			re = NULL;
		}
	}
	int* re;
};

void test4()
{
	sd* sd1 = new er(18);//多态的调用条件之一: 父类指针指向子类成员函数 
	delete sd1;//通过父类指针释放子类对象
	// 1. 当 子类 以正常方式编写时 上两句代码并不能 触发 子类(er)的析构函数,导致了 堆区未释放干净
	//
}


//    五. 多态案例三: 工作的电脑

class CPU
{
public:
	virtual void calculate() = 0;//抽象的计算函数
};

class GraphicsCard
{
public:
	virtual void display() = 0;//抽象的显示函数
};

class Memory
{
public:
	virtual void storage() = 0;//抽象的storage函数
};

class Computer
{
public:
	Computer(CPU* Cp, GraphicsCard* Gr, Memory* Me)
	{
		C_CP = Cp;
		C_Gr = Gr;
		C_Me = Me;
	}

	void work()
	{
		//让零件工作起来,调用接口
		C_CP->calculate();
		C_Gr->display();
		C_Me->storage();
	}
	~Computer()
	{
		if (C_CP != NULL)
		{
			delete C_CP;
			C_CP = NULL;
		}
		if (C_Gr != NULL)
		{
			delete C_Gr;
			C_Gr = NULL;
		}
		if (C_Me != NULL)
		{
			delete C_Me;
			C_Me = NULL;
		}
	}
private:
	CPU* C_CP;
	GraphicsCard* C_Gr;
	Memory* C_Me;
};

// 1 厂商
class I_CPU :public CPU
{
public:
	virtual void calculate()
	{
		cout << "Intel的CPU开始计算了!" << endl;
	}
};

class I_GraphicsCard :public GraphicsCard
{
public:
	virtual void display()
	{
		cout << "Intel的显卡开始显示了! " << endl;
	}
};

class I_Memory :public Memory
{
public:
	virtual void storage()
	{
		cout << "Intel的内存条开始存储了!" << endl;
	}
};

// L 厂商
class L_CPU :public CPU
{
public:
	virtual void calculate()
	{
		cout << "L 的CPU开始计算了!" << endl;
	}
};

class L_GraphicsCard :public GraphicsCard
{
public:
	virtual void display()
	{
		cout << "L 的显卡开始显示了! " << endl;
	}
};

class L_Memory:public Memory
{
public:
	virtual void storage()
	{
		cout << "L的内存条开始存储了!" << endl;
	}
};



void test5()
{
	CPU* I_CPU1 = new I_CPU;
	GraphicsCard* GraphicsCard1 = new I_GraphicsCard;
	Memory* Memory1 = new I_Memory;

	cout << "第一台电脑开始工作:" << endl << endl;

	Computer* com1 = new Computer(I_CPU1, GraphicsCard1, Memory1);
	com1->work();
	delete com1;

	cout << "第二台电脑开始工作:" << endl << endl;

	Computer* com2 = new Computer(new L_CPU, new L_GraphicsCard, new L_Memory);
	com2->work();
	delete com2;

	cout << "第三台电脑开始工作:" << endl << endl;

	Computer* com3 = new Computer(new I_CPU, new L_GraphicsCard, new I_Memory);
	com3->work();
	delete com3;
}
int main()
{
	cout << "C++面向对象的三大特性: 封装 继承 多态" << endl;

	cout << "多态 !" << endl;
	test1();

	cout << "二. 多态案例一: 计算器类" << endl;
	test01();
	test2();

	cout << "三. 多态案例二: 制饮料" << endl;
	test3();

	cout << "四. 虚析构 和 纯虚析构" << endl;
	test4();

	cout << "五. 多态案例三: 工作的电脑" << endl;
	test5();

	system("pause");
	return 0;
}

2.运行结果 :

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值