多态的作用-游戏编程展示------新标准c++程序设计
游戏软件的开发最能体现面向对象设计方法的优势。游戏中的人物、道具、建筑物、场景等都是很直观的对象,游戏运行的过程就是这些对象相互作用的过程。每个对象都有自己的属性和方法,不同对象也可能有共同的属性和方法,特别适合使用继承、多态等面向对象的机制。下面就以“魔法门”游戏为例来说明多态在增加程序可扩展性方面的作用。
“魔法门”游戏中有各种各样的怪物,如骑士、天使、狼、鬼,等等。每个怪物都有生命力、攻击力这两种属性。怪物能够相互攻击。一个怪物攻击另一个怪物时,被攻击者会受伤;同时被攻击者会反击,使得攻击者也受伤。但是反击只有其自身攻击力的一半。而且还有各自的攻击、反击动作(省略)
不用多态:
class C_dragon{ //龙
private:
int power; //攻击力
int life_value; //生命值
public:
void Attack(C_wolf* p); //攻击 狼 的成员函数
void Attack(C_ghost* p); //攻击 鬼 的成员函数
//......其他Attack重载函数
//表现受伤的成员函数
void Hurted(int n_power); //被攻击,生命值降低的成员函数
void Fight_back(C_wolf* p); //反击 狼 的成员函数
void Fight_back(C_ghost* p); //反击 鬼 的成员函数
//......其他Fight_back重载函数
};
void C_dragon::Attack(C_wolf* p){
p->Hurted(power);
p->Fight_back(this);
}
void C_dragon::Attack(C_ghost* p){
p->Hurted(power);
p->Fight_back(this);
}
void C_dragon::Hurted(int n_power){
life_value-=n_power;
}
void C_dragon::Fight_back(C_wolf* p){
p->Hurted(power/2);
}
void C_dragon::Fight_back(C_ghost* p){
p->Hurted(power/2);
}
实际上,如果游戏中有n种怪物,C_dragon类中就会有n个Attack成员函数,n个Fight_back成员函数。对于其他类,如C_wolf类等,也是这样。
以上为非多态的实现方法。在增加怪物种类多的时候,工作量会比较大。例如增加怪物“雷鸟”,除了编写一个C_bird类外,所以的类都需要增加一下两个成员函数,用以对“雷鸟”实施攻击,以及被“雷鸟”攻击时的反击:
void Attack(C_bird* p){
p->Attack(power);
p->Fight_back(this);
};
void Fight_back(C_bird* p){
p->Hurted(power/2)
};
实际上,在非多态的实现中,使代码更精简的做法是将C_dragon、C_wolf等类的共同特点抽取出来,形成一个C_creature类,然后再从C_creature类派生出C_dragon、C_wolf等类,但是由于每种怪物的表现动作不同,这些类还要实现各自的Hurted、Attack、Fight_back成员函数。因此,如果没有利用多态机制,那么即便引入基类C_creature,对程序的可扩充性也没有太大帮助。
使用多态:
设置一个基类C_creature,概括所有怪物的共同科殿。所以具体的怪物类,如C_dragon、C_wolf、C_ghost等,均从C_creature类派生而来。
C_creature:
class C_creature{ //“怪物”类
protected:
int life_value,power;
public:
virtual void Attack(C_creature* p){};
virtual void Hurted(int n_power){};
virtual void Fight_back(C_creature* p){};
};
可以看到,基类C_creature中只有一个Attack成员函数,也只有一个Fight_back成员函数。
实际上,所以C_creature类的派生类也都只有一个Attack成员函数和一个Fight_back成员函数。例如 C_dragon类:
class C_dragon::public C_creature{
public:
virtual void Attack(C_creature* p){
p->Attack(power);
p->Fight_back(this);
};
virtual void Hurted(int n_power){
life_value-=n_power;
};
virtual void Fight_back(C_creature* p){
p->Hurted(power/2)
};
};
C_dragon类的成员函数中省略了表现动作的那部分代码。其他类的写法和C_dragon类类似,只是实现动作的代码不同。
在上述多态的写法中,当需要增加新怪物“雷鸟”时,只需要编写新类C_bird即可。不需要在已有的类中专门为新怪物增加:
void Attack(C_bird* p){
p->Attack(power);
p->Fight_back(this);
};
void Fight_back(C_bird* p){
p->Hurted(power/2)
};
这两个成员函数,也就是说,其他类根本不用修改。这样一来跟前面的非多态方法相比,程序的可扩充性大大提高了。
新标准c++程序设计
多态的作用-游戏编程展示------新标准c++程序设计的更多相关文章
- 在成员函数中调用虚函数(关于多态的注意事项)------新标准c++程序设计
类的成员函数之间可以互相调用.在成员函数(静态成员函数.构造函数和析构函数除外)中调用其他虚成员函数的语句是多态的.例如: #include<iostream> using namespa ...
- 多态实现的原理------新标准c++程序设计
“多态”的关键在于通过基类指针或引用调用一个虚函数时,编译时不确定到底调用的是基类还是派生类的函数,运行时才确定.例子: #include<iostream> using namespac ...
- 类型转换构造函数 及使用explicit避免类型自动转换------新标准c++程序设计
类型转换构造函数: 除复制构造函数外,只有一个参数的构造函数一般可以称作类型转换构造函数,因为这样的构造函数能起到类型自动转换的作用.例如下面的程序: #include<iostream> ...
- this指针------新标准c++程序设计
背景: c++是在c语言的基础上发展而来的,第一个c++的编译器实际上是将c++程序翻译成c语言程序,然后再用c语言编译器进行编译.c语言没有类的概念,只有结构,函数都是全局函数,没有成员函数.翻 ...
- 指针和动态分配内存 (不定长度数组)------新标准c++程序设计
背景: 数组的长度是定义好的,在整个程序中固定不变.c++不允许定义元素个数不确定的数组.例如: int n; int a[n]; //这种定义是不允许的 但是在实际编程中,往往会出现要处理的数据数量 ...
- 正确处理类的复合关系------新标准c++程序设计
假设要编写一个小区养狗管理程序,该程序需要一个“主人”类,还需要一个“狗”类.狗是有主人的,主人也有狗.假定狗只有一个主人,但一个主人可以有最多10条狗.该如何处理“主人”类和“狗”类的关系呢?下面是 ...
- 类与类之间的两种关系------新标准c++程序设计
在c++中,类和类之间有两种基本关系:复合关系和继承关系. 复合关系也称为“has a”关系或“有”的关系,表现为封闭类,即一个类以另一个类的对象作为成员变量. 继承关系也称为“is a”关系或“是” ...
- 复制构造函数被调用的三种情况------新标准c++程序设计
1.当用一个对象去初始化同类的另一个对象时,会引发复制构造函数被调用.例如,下面的两条语句都会引发复制构造函数的调用,用以初始化c2. C c2 (c1); C c2=c1; 这两条语句是等价的.注意 ...
- 析构函数的调用------新标准c++程序设计
示例1: #include<iostream> using namespace std; class CDemo{ public: ~CDemo(){cout<<"d ...
随机推荐
- 根据MAC地址前6位知道网络设备是哪家公司生产的
http://standards-oui.ieee.org/oui/oui.txt https://files.cnblogs.com/files/itfat/oui.rar
- python中的enumerate函数用于遍历序列中的元素以及它们的下标
enumerate 函数用于遍历序列中的元素以及它们的下标: >>> for i,j in enumerate(('a','b','c')): print i,j 0 a1 b2 c ...
- Cassandra学习六 一些知识点
http://www.flyml.net/2016/09/08/cassandra-tutorial-java-api-example/ Cassandra对查询的支持很弱,只支持主键列及索引列的查询 ...
- 进程句柄和进程ID的区别和关系
进程和进程句柄和进程id含义 进程是一个正在运行的程序,进程里可以包括多个模块(DLL,OCX,等)进程句柄是程序访问时用到的东西,当前进程句柄等于主模块的句柄,当你使用OpenProcess时的进程 ...
- vue-cli脚手架config目录下index.js配置文件详解
此文章介绍vue-cli脚手架config目录下index.js配置文件 此配置文件是用来定义开发环境和生产环境中所需要的参数 关于注释 当涉及到较复杂的解释我将通过标识的方式(如(1))将解释写到单 ...
- 实用webpack-dev-server
webpack-dev-server的作用 文件作出改动之后,保存,立即开始编译文件 编译后的文件是保存在内存中的,在项目文件夹中看不到编译后的文件 编译完成之后立即自动刷新浏览器 测试webpack ...
- nginx keepalive 双机
Nginx+keepalived双机热备(主从模式) 负载均衡技术对于一个网站尤其是大型网站的web服务器集群来说是至关重要的!做好负载均衡架构,可以实现故障转移和高可用环境,避免单点故障,保证网 ...
- 利用jquery mobiscroll插件选择日期、select、treeList的具体运用
体验更优排版请移步原文:http://blog.kwin.wang/programming/jquery-mobiscroll-select-treeList.html mobiscroll是个很好用 ...
- wordpress 基础文件
需要用到的PHP基础文件有: 404.php 404模板 rtl.css 如果网站的阅读方向是自右向左的,会被自动包含进来 comments.php 评论模板 single.php 文章模板.显 ...
- mysql 存储过程 编写注意事项
mysql的存储过程有很多需要注意的地方,一不留神就会出错,可能调试了老半天才发现原因 1 没有return 语句 可以采用leave代替,返回直接使用select语句 比如select 1: 2. ...