在面向对象的程序设计中,使用多态能够增强程序的可扩充性,即程序需要修改或增加功能时,只需改动或增加较少的代码。此外,使用多态也能起到精简代码的作用。本节通过两个实例来说明多态的作用。
游戏程序实例
游戏软件的开发最能体现面向对象设计方法的优势。游戏中的人物、道具、建筑物、场景等都是很直观的对象,游戏运行的过程就是这些对象相互作用的过程。每个对象都有自己的属性和方法,不同对象也可能有共同的属性和方法,特别适合使用继承、多态等面向对象的机制。下面就以“魔法门”游戏为例来说明多态在增加程序可扩充性方面的作用。

“魔法门”游戏中有各种各样的怪物,如骑士、天使、狼、鬼,等等。每个怪物都有生命力、攻击力这两种属性。怪物能够互相攻击。一个怪物攻击另一个怪物时,被攻击者会受伤;同时,被攻击者会反击,使得攻击者也受伤。但是一个怪物反击的力量较弱,只是其自身攻击力的 1/2。

怪物主动攻击、被敌人攻击和实施反击时都有相应的动作。例如,骑士的攻击动作是挥舞宝剑,而火龙的攻击动作是喷火;怪物受到攻击会嚎叫和受伤流血,如果受伤过重,生命力被减为 0,则怪物就会倒地死去。

针对:这个游戏,该如何编写程序,才能使得游戏版本升级、要增加新的怪物时,原有的程序改动尽可能少呢?换句话说,如何才能使程序的可扩充性更好呢?

然而,无论是否使用多态,均应使每种怪物都有一个类与之对应,每个怪物就是一个对象。而且,怪物的攻击、反击和受伤等动作都是通过对象的成员函数实现的,因此需要为每个类编写 Attack、FightBack 和 Hurted 成员函数。

Attack 成员函数表现攻击动作,攻击某个怪物并调用被攻击怪物的 Hurted 成员函数,以减少被攻击怪物的生命值,同时也调用被攻击怪物的 FightBack 成员函数,遭受被攻击怪物的反击。

Hurted 成员函数减少自身生命值,并表现受伤动作。

FightBack 成员函数表现反击动作,并调用被反击对象的 Hurted 成员函数,使被反击对象受伤。

下面对比使用多态和不使用多态两种写法,来看看多态在提高程序可扩充性方面的作用。

先介绍不用多态的写法。假定用 CDmgon 类表示龙,用 CWolf 类表示狼,用 CGhost 类表示鬼,则 CDragon 类的写法大致如下(其他类的写法与之类似):

class CDragon
{private:int power;  //攻击力int lifeValue;  //生命值
public:void Attack(CWolf * p);  //攻击“狼”的成员函数void Attack(CGhost* p);  //攻击“鬼”的成员函数//……其他 Attack 重载函数//表现受伤的成员函数void Hurted(int nPower);void FightBack(CWolf * p);  //反击“狼”的成员函数void FightBack(CGhost* p);  //反击“鬼”的成员函数//......其他FightBack重载函数
};

各成员函数的写法如下:

void CDragon::Attack(CWolf* p)
{p->Hurted(power);p->FightBack(this);
}
void CDragon::Attack(CGhost* p)
{p->Hurted(power);p->FightBack(this);
}
void CDragon::Hurted(int nPower)
{lifeValue -= nPower;
}
void CDragon::FightBack(CWolf* p)
{p->Hurted(power / 2);
}
void CDragon::FightBack(CGhost* p)
{p->Hurted(power / 2);
}

第 1 行,Attack 函数的参数 p 指向被攻击的 CWolf 对象。

第 3 行,在 p 所指向的对象上面执行 Hurted 成员函数,使被攻击的“狼”对象受伤。调用 Hurted 成员函数时,参数是攻击者“龙”对象的攻击力。

第 4 行,以指向攻击者自身的 this 指针为参数,调用被攻击者的 FightBack 成员函数,接受被攻击者的反击。

在真实的游戏程序中,CDragon 类的 Attack 成员函数中还应包含表现“龙”在攻击时的动作和声音的代码。

第 13 行,一个对象的 Hurted 成员函数被调用会导致该对象的生命值减少,减少的量等于攻击者的攻击力。当然,在真实的程序中,Hurted 成员函数还应包含表现受伤时动作的代码,以及生命值如果减至小于或等于零,则倒地死去的代码。

第 17 行,p 指向的是实施攻击者。对攻击者进行反击,实际上就是调用攻击者的 Hurted 成员函数使其受伤。其受到的伤害的大小等于实施反击者的攻击力的一半(反击的力量不如主动攻击大)。当然,FightBack 成员函数中其实也应包含表现反击动作的代码。

实际上,如果游戏中有 n 种怪物,CDragon 类中就会有 n 个 Attack 成员函数,用于攻击 n 种怪物。当然,也会有 71 个 FightBack 成员函数(这里假设两条龙也能互相攻击)。对于其他类,如 CWolf 类等,也是这样。

以上为非多态的实现方法。如果游戏版本升级,增加了新的怪物“雷鸟”,假设其类名为 CThunderBird,则程序需要做哪些改动呢?

除了编写一个 CThiinderBird 类外,所有的类都需要增加以下两个成员函数,用以对“雷鸟”实施攻击,以及在被“雷鸟”攻击时对其进行反击:

void Attack(CThunderBird* p);
void FightBack(CThunderBird* p);

这样,在怪物种类多的时候,工作量会比较大。

实际上,在非多态的实现中,使代码更精简的做法是将 CDragon、CWolf 等类的共同特点 抽取出来,形成一个 CCreature 类,然后再从 CCreature 类派生出 CDragon、CWolf 等类。但是由于每种怪物进行攻击、反击和受伤时的表现动作不同,CDmgon、CWdf 这些类还要实现各自的 Hurted 成员函数,以及一系列 Attack、FightBack 成员函数。因此,如果没有利用多态机制,那么即便引人基类 CCreature,对程序的可扩充性也没有太大帮助。

下面再来看看,如果使用多态机制编写这个程序,在要新增 CThunderBird 类时,程序改动的情况。使用多态的写法如下:设置一个基类 CCreature,概括所有怪物的共同特点。所有具体的怪物类,如 CDragon、CWolf、CGhost 等,均从 CCreature 类派生而来。下面是 CCreature 类的写法:

class CCreature {  //“怪物”类
protected:int lifeValue, power;
public:virtual void Attack(CCreature* p) {};virtual void Hurted(int nPower) {};virtual void FightBack(CCreature* p) {};
};

可以看到,基类 CCreature 中只有一个 Attack 成员函数,也只有一个 FightBack 成员函数。

实际上,所有 CCreature 类的派生类也都只有一个 Attack 成员函数和一个 FightBack 成员函数。例如,CDragon 类的写法如下:

class CDragon : public CCreature
{public:virtual void Attack(CCreature* p) {p->Hurted(power);p->FightBack(this);}virtual int Hurted(int nPower) {lifeValue -= nPower;}virtual int FightBack(CCreature* p) {p->Hurted(power / 2);}
};

CDragon 类的成员函数中省略了表现动作和声音的那部分代码。其他类的写法和 CDragon 类类似,只是实现动作和声音的代码不同。如何实现动画的动作和声音不是本书要讲述的内容。

在上述多态的写法中,当需要增加新怪物“雷鸟”时,只需要编写新类 CThunderBird 即可,不需要在已有的类中专门为新怪物增加 void Attack(CThunderBird * p) 和 void FightBack(CThunderBird* p) 这两个成员函数。也就是说,其他类根本不用修改。这样一来,和前面非多态的实现方法相比,程序的可扩充性当然大大提高了。实际上,即便不考虑可扩充性的问题,程序本身也比非多态的写法大大精简了。

为什么 CDragon 等类只需要一个 Attack 函数,就能够实现对所有怪物的攻击呢?

假定有以下代码片段:
CDragon dragon;
CWolf wolf;
CGhost ghost;
CThunderBird bird;
Dragon.Attack(&wolf);
Dragon.Attack(&ghost);
Dragon.Attack(&bird);

根据赋值兼容规则,上面第 5、6、7 行中的参数都与基类指针类型 CCreature* 相匹配,所以编译没有问题。从 5、6、7 三行进入 CDragon::Attack 函数后,执行 p-> Hurted(power) 语句时,p 分别指向的是 wolf、ghost 和 bird,根据多态的规则,分别调用的就是 CWolf::Hurted、CGhost::Hurted 和 CBird: Hurted 函数。

FightBack 函数的情况和 Attack 函数类似,不再赘述。

几何形体程序实例
例题:编写一个几何形体处理程序,输入几何形体的个数以及每个几何形体的形状和参数,要求按面积从小到大依次输出每个几何形体的种类及面积。假设几何形体的总薮不超过 100 个。

例如,输入
4
R 3 5
C 9
T 3 4 5
R 2 2

表示一共有 4 个几何形体,第一个是矩形(R 代表矩形),宽度和高度分别是 3 和 5;第二个是圆形(C 代表圆形),半径是 9;第三个是三角形(T代表三角形),三条边的长度分别是 3,4,5;第四个是矩形,宽度和高度都是 2。

应当输出:
Rectangle:4
Triangle:6
Rectangle:15
Circle:254.34

该程序可以运用多态机制编写,不但便于扩充(添加新的几何形体),还能够节省代码量。程序如下:

多态 在游戏程序实例相关推荐

  1. C++多态的好处和作用(游戏程序实例)

    http://c.biancheng.net/view/265.html 在面向对象的程序设计中,使用多态能够增强程序的可扩充性,即程序需要修改或增加功能时,只需改动或增加较少的代码.此外,使用多态也 ...

  2. 强化学习(三) - Gym库介绍和使用,Markov决策程序实例,动态规划决策实例

    强化学习(三) - Gym库介绍和使用,Markov决策程序实例,动态规划决策实例 1. 引言 在这个部分补充之前马尔科夫决策和动态规划部分的代码.在以后的内容我会把相关代码都附到相关内容的后面.本部 ...

  3. 微信小程序实例源码大全demo下载

    怎么本地测试微信小程序实例源码 1.下载源码 2.打开微信开发者工具 3.添加项目->选择本项目目录->编译执行 微信小程序实例源码大全 微信小程序游戏类demo:识色:从相似颜色中挑选不 ...

  4. 《Unity 3.x游戏开发实例》一1.5 欢迎来到Unity 3D

    本节书摘来异步社区<Unity 3.x游戏开发实例>一书中的第1章,第1.5节,作者: [加]Ryan Henson Creighton 译者: 师蓉 责编: 陈冀康,更多章节内容可以访问 ...

  5. c语言220程序,《C语言程序实例大全》原代码220例

    <C语言程序实例大全>,一共220个. 找了很多地方都不全,最后在CSDN上用积分下载了这个,C语言初学者可以参考. 下载地址: http://doc.xuehai.net/tp09770 ...

  6. java四子棋实验报告_Python 实现劳拉游戏的实例代码(四连环、重力四子棋)

    游戏规则:双方轮流选择棋盘的列号放进自己的棋子, 若棋盘上有四颗相同型号的棋子在一行.一列或一条斜线上连接起来, 则使用该型号棋子的玩家就赢了! 程序实现游戏,并将每局的数据保存到本地的文件中 首先我 ...

  7. python编程手机模拟点击_python模拟点击玩游戏的实例讲解

    小编发现很多小伙伴都喜欢玩一些游戏,而手游因为玩的场景限制不多,所以受众的人更多.游戏里有很多重复的任务需要我们完成,虽然过程非常无聊,但是为了任务奖励还是有很多小伙伴不厌其烦的去做.那么,有没有什么 ...

  8. 游戏程序中的骨骼插件

    如有转载,请详细标明原文作者,以示尊重! 作者:潘李亮 转自:http://www.cppblog.com/lai3d/archive/2009/07/11/89768.html 游戏程序中的骨骼插件 ...

  9. 一个完整的Installshield安装程序实例

    一个完整的Installshield安装程序实例-艾泽拉斯之海洋女神出品(一)---基本设置一 前言 Installshield可以说是最好的做安装程序的商业软件之一,不过因为功能的太过于强大,以至于 ...

最新文章

  1. [转]Visual Studio 2010帮助文件MSDN安装说明
  2. c# GDI+简单绘图(一)
  3. RAID 01 和RAID 10的区别
  4. AI:初学者如何从零学习人工智能?看完你就懂了
  5. php 正则匹配静态资源,Struts2 配置静态资源文件不经过Strut处理(正则匹配)
  6. 悉数11种主流NoSQL文档型数据库
  7. php7 opcode,php7最小化安装 vld扩展安装并查看php代码的opcode ast测试
  8. java中==与equals的区别及理解_Java开发中常量池的理解与归纳
  9. Web页面输出Excel的数字问题解决方法
  10. swagger2 配置访问路径_有了Swagger2 再也不用担心API文档的维护了
  11. 外贸最全出口流程,外贸必看基础知识
  12. K13318 破译信息
  13. img loading=“lazy“ 是什么意思?
  14. 经典括号匹配问题——你真的明白了吗?
  15. OpenCv图像处理实战——银行卡卡号识别
  16. Java、JSP高速公路收费系统
  17. 抖音短视频吃鸡戏精野生脆脆如何上的热门
  18. 启用计算机无线网络连接,哪位清楚笔记本电脑如何启用无线网络连接
  19. Android Studio:Type mismatch: inferred type is Int but Unit was expected
  20. 网页制作-第一周-任务1_1网页和网站的概念

热门文章

  1. 图解ARP协议(三)ARP防御篇-如何揪出内鬼并优雅的还手
  2. Word图片上传控件(WordPaster)更新-2.0.15版本
  3. 15天深度复习JavaWeb的详细笔记(四)——HTML、CSS
  4. PHP将Word转PDF文件
  5. 电脑上传网速怎么测试软件,Win7如何测试电脑上传速度?
  6. ffmpeg h265
  7. MAC版 破解百度云、百度网盘限速的方法
  8. 简单使用hbuildx把vue-cli项目打包,并使用electron转换成可执行的exe文件
  9. 南加利福尼亚大学计算机博士,斑马博士|南加州大学(USC) MSc Electronic Engineering (Computer Network)...
  10. 快速傅里叶变换(FFT)(学习笔记)