用游戏编程实例进行C++“多态”概念教学
摘要:“多态”是面向对象程序设计方法中的重要概念,也是提高程序可扩充性的重要手段。然而初学面向对象编程的学生往往难以真正体会到其作用。文章介绍一个在教学中沿用多年,能够生动而充分地展示多态的作用,并在教学比赛中获奖的游戏编程教学案例,供大家参考。
关键词:多态;可扩充性;虚函数;抽象类
1问题的提出
面向对象程序设计语言有封装、继承和多态三种机制,这三种机制能够有效提高程序的可读性、可扩充性和可重用性。
而“多态”(Polymorphism),可以分为编译时的多态和运行时的多态。
编译时的多态,主要指的是运算符的重载和函数的重载。这部分内容,比较简单,易于理解,本文并不打算讨论。
运行时的多态,指的是以下机制(本文以后提到的“多态”,都指的是运行时的多态):
对于通过基类指针,调用基类和派生类中都有的同名、同参数表的虚函数这样的语句,编译时并不确定要执行的是基类还是派生类的虚函数;而当程序运行到该语句时,如果该基类指针指向的是一个基类对象,则基类的虚函数被执行,如果该基类指针指向的是一个派生类对象,则派生类的虚函数被执行(将上面表述中的“指针”换成“引用”,同样成立)。
多态可以简单地理解成同一条函数调用语句能调用不同的函数,或者说,对不同对象发送同一消息,使得不同对象有各自不同的行为。
多态在面向对象的程序设计语言中是如此重要,以至于有类和对象的概念,但是不支持多态的语言,只能被称作“基于对象的程序设计语言”,而不能被称为“面向对象的程序设计语言”。如Visual Basic就是“基于对象的程序设计语言”。
让学生掌握多态的语法规则并不难,难的是让他们深刻理解多态到底有什么用处。实际上,在面向对象的编程中使用多态,能够有效地提高程序的可扩充性,这就是多态最大的作用。
所谓一个程序的可扩性好,指的就是当该程序的功能需要增加或修改时,只需改动或增加比较少的代码就能实现。往往,一个程序员只有在编写了一定规模的程序,并且等到其程序真
正需要添加新功能的时候,才能切身体会到程序的可扩充性是多么重要。那么,怎样才能让没有多少编程经历的低年级学生,不需要编写大规模的程序就能体会到多态在提高程序可扩充性方面的作用呢?这就是本文要探讨的问题。
2问题的现状
笔者查阅多本流行的C++教材,这些教材和讲义大多对多态提高程序的可扩充性这个作用未能充分展示。这些教材在阐述多态时,所举的例子一般都是这样的:
开设一个基类指针数组,该数组里的指针,有的指向基类对象,有的指向派生类对象。在此种情况下,遍历该数组,对每个数组元素,均通过它去调用基类和派生类里都有的同名虚函数,这就达到了在每个对象上都执行它自己的虚函数的目的[2]。例如,一个几何形体演示程序,有基类Shape,还有Rectangle,Triangle和Circle等Shape的派生类,这些类都有虚函数double Area()用以计算图形的面积。那么要计算所有几何图形的面积,只需用一个Shape * 类型的数组,存放所有几何图形对象的地址,然后遍历该数组,对每个元素(即类型为Shape * 的变量)均通过它去调用Area()虚函数,那么多态机制就能确保每个几何图形的面积都是用正确的Area()函数计算出来的[3]。
这样的例子,说明使用多态能够某种程度上精简程序的代码,但不能很好地说明多态在增强可扩充性方面的作用。比较好的例子应该是用多态和非多态的方法各写一段程序,然后要求对该程序进行功能上的扩充,此时再来看这两段程序各要做多大的改动——这才能够充分体现多态的优势。
笔者看到的教材里,只有一部采用了这样的写法[1]。该书举了一个异质链表(同一链表里存放不同类型的对象)的例子。该例子能够充分说明多态的优点,但是略显冗长,不够生动有趣,也不像实践中的例子。
那么软件开发的实践中,能否到生动有趣而又不冗长的例子,来充分说明多态在程序可扩充性方面的作用呢?答案是肯定的,那就是到游戏开发中去寻案例。
3问题的解决
游戏软件的开发,是最能体现面向对象设计方法的优势的。游戏中的人物、道具、建筑物、场景,都是很直观的对象,游戏运行的过程,就是这些对象相互作用的过程。每个对象都有自己的属性和方法,不同对象又可能有共同的属性和方法,特别适合使用继承、多态等面向
对象的机制。而且,游戏本来就是学生所津津乐道的,在课堂的PPT里放几张游戏的截图,学生精神就会为之一振,兴趣大增。因此,笔者在讲述“多态”这一概念的时候,以“魔法门之英雄无敌”游戏的开发为例,充分论述了多态在提高程序可扩充性方面的作用,让同学们不但能学得明白,还能学得有趣。
“魔法门”游戏中有各种各样的怪物,如骑士、天使、狼,鬼,等等。每个怪物都有生命力、攻击力这两种属性。怪物能够互相攻击,一个怪物攻击另一个怪物时,会使被攻击者受伤;同时被攻击者会反击,使得攻击者也受伤。但是一个怪物反击的力量较弱,只是其自身攻击力的1/2。
怪物主动攻击、被敌人攻击和实施反击时都有相应的动作。比如骑士攻击时的动作就是挥舞宝剑,而火龙的攻击动作就是喷火;怪物受到攻击会嚎叫和受伤流血,如果受伤过重,生命力被减为0,则怪物就会倒地死去…….
针对这个游戏,教师提出的问题是:该如何编写程序,才能使得游戏版本升级,要增加新的怪物时,原有的程序改动尽可能少 。换句话说,就是怎样才能使程序的可扩充性更好。
显然,不论是否使用多态,均应使每种怪物都有一个类与之对应,每个怪物就是一个对象。而且,怪物的攻击、反击和受伤等动作,都是通过对象的成员函数实现的,因此为每个类都需要编写Attack、FightBack和 Hurted成员函数
Attact函数表现攻击动作,攻击某个怪物,并调用被攻击怪物的 Hurted函数,以减少被攻击怪物的生命值,同时也调用被攻击怪物的 FightBack成员函数,遭受被攻击怪物反击。
Hurted函数减少自身生命值,并表现受伤动作。
FightBack成员函数表现反击动作,并调用被反击对象的Hurted成员函数,使被反击对象受伤。
接下来就是对比使用多态和不使用多态两种写法,来体现多态在提高程序可扩充性方面的作用。
先看不用多态的写法。假定用“CDragon”类表示火龙,用“CWolf”类表示狼,用“CGhost”类表示鬼,则“CDragon”类写法大致如下(其他类的写法也类似):
class CDragon
{
private:
int m_nPower ; //攻击力
int m_nLifeValue ; //生命值
public:
//攻击“狼”的成员函数
void Attack(CWolf * p);
//攻击“鬼”的成员函数
void Attack(CGhost * p);
//......其他Attack重载函数
//表现受伤的成员函数
void Hurted( int nPower);
//反击“狼”的成员函数
void FightBack(CWolf * p);
//反击“鬼”的成员函数
void FightBack(CGhost * p);
关于FightBack函数的情况,和Attack类似,不再赘述。
至此,多态对提高程序可扩充性的作用,在这个游戏编程的实例中,得到了生动而充分的展示。再辅以在本文第二节中提到的那种例子,同学们对于多态的理解,就会非常深刻。
4结语学编程的游戏app
本文中的游戏编程实例,连续多个学年在北京大学信息学院主干基础课“程序设计实习”(其包含C++内容)的课堂上讲述,收到了很好的效果。同学们纷纷反映,很希望C++的其他内容的
授课,也能像“多态”这一节那样精彩。笔者以此部分内容参加了北京大学青年教师教学基本功和现代教育技术应用演示竞赛,获得理工类三等奖;参加北京市“计算机技术教育课堂教学交流”学术年会,获得三等奖。
由此笔者得到一个启发:游戏开发是面向对象的程序设计方法的典型应用,学生们又对游戏如此喜闻乐见,那么,在面向对象程序设计语言的教学中,多引入一些游戏相关的例子程序,一定能广受学生欢迎。笔者据此思想改造了C++讲义,并且设计了一个需要熟练运用面向对象的各种机制,才能高效完成的期末大作业,一道类似游戏的模拟题——魔兽世界,放在了北京大学在线程序评测系统POJ上。
参考文献:
[1] 宛延闿. C++语言面向对象程序设计[M]. 北京:清华大学出版社,1998:168-190.
[2] 郑莉,董渊,张瑞丰. C++语言程序设计[M]. 3版. 北京:清华大学出版社,2004:274-280.
[3] Harvey M. Deitel,Paul James Deitel. C++大学教程[M]. 2版. 邱仲潘,等译. 北京:电子工业出版社,2001:425-431.
Teaching the “Polymorphism” Conception by a Sample of Game Programming
GUO Wei
Abstract: Polymorphism is a very important concept in object oriented programming, and it’s also a very important method to improve the program extensibility. But it’s a little bit hard for the beginner to really understand the advantage of polymorphism. This article introduces a game programming sample, which can demonstrate the advantage of polymorphism vividly. And this teaching case won awards in some teaching contests.
Key words: polymorphism; extensibility; virtual function; abstract class
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论