C++动态多态详解及三个示例

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

多态分为两类

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

动态多态实现分三步:(代码中具体步骤用 【】标识)

  • 子类重写父类的虚函数(类内实现)
  • .父类指针指向子类对象(类外实现)
  • .用该指针调用子类虚函数(类外实现)

案例一:

实现代码框架是:

class Basic
{
public:
	virtual void exeGame() = 0;		// 纯虚函数
}
class TCSGame :public BasicGame	//继抽象类 BasicGame
{
public:
	virtual void exeGame()		// 【步骤一】 重写虚函数
	{
	}
}
void test()
{
	Basic *b = new TCSGame();	//【步骤二】父类指针指向子类对象
	b->exeGame(); //【步骤三】 用该指针调用子类虚函数
	// 注:用引用的方式也可以,因为引用的本质也是指针
}

具体实现代码

#include<iostream>
#include<string>
#include<windows.h>
using namespace std;
class BasicGame		// 抽象类
{
public:
	virtual void exeGame() = 0;		// 纯虚函数
};
class TCSGame :public BasicGame	//继抽象类 BasicGame
{
public:
	TCSGame(string name)	//构造函数
	{
		m_Name = name;
	}
	virtual void exeGame()	// 【步骤一】 重写虚函数, virtual 可要可不要
	{
		cout << "运行游戏:" << m_Name << endl;
	}
public:
	string m_Name;
};

class WingGame :public BasicGame	//继抽象类 BasicGame
{
public:
	WingGame(string name)	//构造函数
	{
		m_Name = name;
	}
	virtual void exeGame()	// 【步骤一】 重写虚函数, virtual 可要可不要
	{
		cout << "运行游戏:" << m_Name << endl;
	}
public:
	string m_Name;
};

void test01()
{
	BasicGame *game;
	game = new TCSGame("贪吃蛇");	// 【步骤二】 父类指针指向子类TCSGame对象
	game->exeGame();	// 【步骤三】:用该指针,调用子类的虚函数
	cout << "****************" << endl;
	game = new WingGame("魂斗罗");	// 【步骤二】 父类指针指向子类WingGame对象
	game->exeGame();
	return;
}
int main()
{
	test01();
	system("pause");
	return 0;
}

说明:使用动态多态的好处是,组织结构很清晰,便于扩展和维护;如果不用多态,而是在一个类里面实现多种功能,比如 上面的两个游戏,如果数量多了会麻烦,而且可读性不好,而且对代码来说,尽量不要改动之前的代码。读者有兴趣可以不用多态实现上面的功能,对比一下。
注: 如果对多态 不是很了解 的话,建议先弄懂案例一,再看下面的

案例二

多态非常的灵活,可以在函数传参时实现多态的赋值(步骤2)
实现代码框架是:

class Basic
{
friend void func(Basic *b);	//抽象类声明友元函数
public:
	virtual void exeGame() = 0;		// 纯虚函数
};
class TCSGame :public BasicGame	//继抽象类 BasicGame
{

public:
	virtual void exeGame()		// 【步骤一】 重写虚函数
	{
	}
};
class WingGame :public BasicGame	//继抽象类 BasicGame
{
public:
	virtual void exeGame()		// 【步骤一】 重写虚函数
	{
	}
};
void func(Basic *b){}
void test()
{
	Basic *b = new TCSGame();	//【步骤二】父类指针指向子类对象
	func(b) //【步骤三】 用该指针调用子类虚函数
	// 注:用引用的方式也可以,因为引用的本质也是指针
}

具体实现代码:


#include<iostream>
#include<string>
#include<windows.h>
using namespace std;
class BasicGame
{
	friend void func(BasicGame *b);		// 这里声明全局友元函数,方便调用 成员变量
public:
	virtual void exeGame() = 0;		// 纯虚函数
};
class TCSGame :public BasicGame	//继抽象类 BasicGame
{
public:
	TCSGame(string name) {
		m_Name = name;
	}
	virtual void exeGame()		// 【步骤一】 重写虚函数
	{
		cout << "运行游戏:" << m_Name << endl;
	}
public:
	string m_Name;
};
class WingGame :public BasicGame	//继抽象类 BasicGame
{
public:
	WingGame(string name) {
		m_Name = name;
	}
	virtual void exeGame()		// 【步骤一】 重写虚函数
	{
		cout << "运行游戏:" << m_Name << endl;
	}
public:
	string m_Name;
};
void func(BasicGame *b) {
	b->exeGame();	// 【步骤三】用父类指针调用子类的虚函数
};
void test()
{
	BasicGame *b;
	b = new TCSGame("贪吃蛇");	//【步骤二】父类指针指向子类对象
	func(b);	// 将 指针传入
	b = new WingGame("魂斗罗");	//【步骤二】父类指针指向子类对象
	func(b); // 将 指针传入
}
int main()
{
	test();
	system("pause");
	return 0;
}

说明: 其实步骤二和步骤一是一样的,只不过多了一个传参而已;但是这种形式更加 方便

案例三

既然 步骤2可以用函数传参 的方式实现,那么构造函数 使用该方式是没有问题的;
代码框架:

class Basic		// 抽象类
{
public:
	virtual void exeFunc() = 0;	//纯虚函数
	int A;
	int B;
};
class exam1:public Basic	// 继承抽象类
{
public:
	exam1(int a, int b){}	// 构造函数
	void exeFunc(){}	// 【步骤一】重写虚函数
};
class Act	// 主类
{
public:
	Act(Basic *b){}	// 【步骤二】父类指针指向子类对象(传参)

public:
	 Basic *m_B;	// 将一个类对象的成员变量
};
void test()
{
	Basic *b = new exam1(10,20); //  【步骤二】父类指针指向子类对象
	Act act = Act(b);  //  【步骤二】父类指针指向子类对象(传参)
	act.m_B->exeFunc();//  【步骤三】父类指针调用子类虚函数
}

具体实现代码如下:

#include<iostream>
#include<string>
#include<windows.h>
using namespace std;
class Basic
{
public:
	virtual void exeFunc() = 0;	//纯虚函数
	int A;
	int B;
};
class exam1 :public Basic	// 继承抽象类
{
public:
	exam1(int a, int b)
	{
		A = a;
		B = b;
	}
	void exeFunc()	// 【步骤一】重写虚函数
	{
		cout << "A=" << A << ",B=" << B << endl;
	}
};
class Act
{
public:
	Act(Basic *b)	// 【步骤二】父类指针指向子类对象
	{
		m_B = b;
	}
public:
	Basic *m_B;
};
void test01()
{
	Basic *b = new exam1(10, 20); //  【步骤二】父类指针指向子类对象
	Act act = Act(b);  //  【步骤二】父类指针指向子类对象(传参)
	act.m_B->exeFunc();
}
int main()
{
	test01();
	system("pause");
	return 0;
}

说明: 案例三,有 继承且 将 类对象做成员变量时,会很方便
如果以上都弄明白了,可以尝试一下下面这个案例:
代码如下

#include<iostream>
#include<string>
#include<map>
#include<stdlib.h>
#include <typeinfo> 
using namespace std;

// 抽象cpu类
class CPU
{
public:
	virtual void calculate() = 0;
};
class InterCPU:public CPU
{
public:
	virtual void calculate()
	{
		cout << "InterCpu 开始工作" << endl;
	}
};
class AMDCPU:public CPU
{
public:
	virtual void calculate()
	{
		cout << "AMDCpu 开始工作" << endl;
	}
};

// 抽象内存类
class Memory
{
public:
	virtual void storage() = 0;
};
class InterMemory:public Memory
{
public:
	virtual void storage()
	{
		cout << "InterMemory 开始工作" << endl;
	}
};
class AMDMemory:public Memory
{
public:
	virtual void storage()
	{
		cout << "AMDMemory 开始工作" << endl;
	}
};
// 抽象cpu类
class VCard
{
public:
	virtual void show() = 0;
};
class InterVCard :public VCard
{
public:
	virtual void show()
	{
		cout << "InterCard 开始工作" << endl;
	}
};
class AMDVCard:public VCard
{
public:
	virtual void show()
	{
		cout << "AMDVCard 开始工作" << endl;
	}
};



class Computer
{
public:
	Computer(CPU *c, Memory *m, VCard *v, string name)
	{
		cpu = c;
		mem = m;
		vc = v;
		this->name = name;
	}
	void work()
	{
		cout << name << "启动" << endl;
		cpu->calculate();
		mem->storage();
		vc->show();
	}
	void mountWork(CPU *c, Memory *m, VCard *v) {
		cout << name << "电脑启动加载硬件" << endl;
		c->calculate();
		m->storage();
		v->show();
	}
public:
	CPU *cpu;
	Memory *mem;
	VCard *vc;
	string name;
};
void test01()
{
	InterVCard *interVc = new InterVCard();
	AMDVCard *amdVc = new AMDVCard();
	InterMemory *interMem = new InterMemory();
	AMDMemory *amdMem = new AMDMemory();
	InterCPU *interCpu = new InterCPU();
	AMDCPU *amdCpu = new AMDCPU();
	Computer huaweiCom = Computer(amdCpu, interMem, interVc, "华为电脑");
	huaweiCom.work();
	cout << "=========================" << endl;
	Computer lenovoCom = Computer(interCpu, interMem, amdVc, "联想电脑");
	lenovoCom.work();
	cout << "=========================" << endl;
	Computer huasuoCom = Computer(interCpu, interMem, interVc, "华所电脑");
	huasuoCom.work();
	cout << "=========================" << endl;
	Computer xiaomiCom = Computer(amdCpu, amdMem, amdVc, "小米电脑");
	xiaomiCom.work();
}

结尾: 以上就是本人对于多态的一些总结,如有不妥之处,请留言一起交流

  • 6
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值