使用多态提高程序扩充性举例(1)——游戏
1、游戏简介
假如一款打怪类的游戏,游戏中有多个不同的怪物:龙、天使、凤凰、士兵等。怪物能够互相攻击,攻击敌人和被攻击时都有相应的动作。动作是通过对象的成员函数实现的。假如现在游戏需要升级:要增加新的怪物–雷鸟。
2、编程的基本思路
- 为每个怪物类编写 Attack、FightBack和 Hurted成员函数。
- Attact函数表现攻击动作,攻击某个怪物,并调用被攻击怪物的Hurted函数,以减少被攻击怪物的生命值,同时也调用被攻击怪物的FightBack成员函数,遭受被攻击怪物反击。
- Hurted函数减少自身生命值,并表现受伤动作。
- FightBack成员函数表现反击动作,并调用被反击对象的Hurted成员函数,使被反击对象受伤。
3、基本代码
设置基类 CCreature,并且使CDragon, CWolf等其他类都从CCreature派生而来。
4、采用非多态的思想实现需求
class class CCreature {
protected:
int nPower ; //代表攻击力
int nLifeValue ; //代表生命值
};
//龙的代码
class CDragon:public CCreature {
public:
void Attack(CWolf * pWolf) {//攻击狼
//...表现攻击动作的代码
pWolf->Hurted( nPower);
pWolf->FightBack( this);
}
void Attack( CGhost * pGhost) {//攻击鬼
//...表现攻击动作的代码
pGhost->Hurted( nPower);
pGohst->FightBack( this);
}
void Hurted ( int nPower) {//自己受伤受伤
//....表现受伤动作的代码
nLifeValue -= nPower;//生命值变低
}
void FightBack( CWolf * pWolf) {//反击狼
//....表现反击动作的代码
pWolf ->Hurted( nPower / 2);
}
void FightBack( CGhost * pGhost) {// 反击鬼
//....表现反击动作的代码
pGhost->Hurted( nPower / 2 );
}
//攻击其他怪物
//反击其他怪物
}
// 其他怪物类同样也需要写类似的代码
有n种怪物,CDragon 类中就会有n个 Attack 成员函数,以及 n个FightBack成员函数。对于其他类也如此。
当游戏升级时,按照这种编程思想,需要修改每一个类(增加两个成员函数:攻击和反击)。这样程序改动非常大。
5、采用多态思想实现需求
class CCreature {
protected :
int m_nLifeValue, m_nPower;
public:
virtual void Attack( CCreature * pCreature) {}
virtual void Hurted( int nPower) { }
virtual void FightBack( CCreature * pCreature) { }
};
class CDragon : public CCreature {
public:
virtual void Attack( CCreature * pCreature);
virtual void Hurted( int nPower);
virtual void FightBack( CCreature * pCreature);
};
void CDragon::Attack(CCreature * p)//接收一个基类指针
{
//...表现攻击动作的代码
p->Hurted(m_nPower); //多态
p->FightBack(this); //多态
}
void CDragon::Hurted( int nPower)
{
//...表现受伤动作的代码
m_nLifeValue -= nPower;
}
void CDragon::FightBack(CCreature * p)//接收一个基类指针
{
//...表现反击动作的代码
p->Hurted(m_nPower/2); //多态
}
//其他怪物也写类似与龙的代码
使用多态思想实现的好处:只需要编写新类CThunderBird, 不需要在已有的类里专门为新怪物增加成员函数:
void Attack( CThunderBird * pThunderBird) ;
void FightBack( CThunderBird * pThunderBird) ;
已有的类可以原封不动,程序改动非常小。
6、使用多态实现该需求的原理
int main(){
CDragon Dragon;
CWolf Wolf;
CGhost Ghost;
CThunderBird Bird;//创建一个 龙、狼、鬼、雷鸟
Dragon.Attack( & Wolf);//(1)龙攻击狼
Dragon.Attack( & Ghost);//(2)龙攻击鬼
Dragon.Attack( & Bird);//(3)龙攻击雷鸟
}
以龙攻击狼为例:
Dragon.Attack( & Wolf);
龙的攻击函数的形参是一个指向基类的指针,而这个指针现在指向一只狼Wolf,当进入龙对象的攻击函数时,首先执行:
p->Hurted(m_nPower); //多态
即,执行受伤函数时,由于p是基类指针,而Hurted是虚函数,因此这条语句使用了多态。由于这里p实际是指向狼对象Wolf的,因此这条语句执行狼 Wolf对象的Hurted函数。这里传递的参数便是这条龙的攻击力,这个参数是protected的,因此基类可以直接访问。因此执行狼的受伤函数时,狼减少对应的血量。