卓航论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 226|回复: 2
打印 上一主题 下一主题

C++编程杂谈之三:面向对象(续)

[复制链接]
[至尊红钻5级]发帖数量≥8000篇 [未点亮至尊黄钻]威望不足10点 [未点亮至尊蓝钻]在线时间不足10小时 [未点亮至尊绿钻]贡献度不足10点 [至尊紫钻4级]金币≥20000个 [未点亮至尊粉钻]精华贴数不足10贴 [未点亮至尊黑钻]活跃不足8个
 等级: 
 级别: 论坛元老
 UID:  7   [未点亮普号显示]钻石不足3个
 阁 分: 36567
 阁 望: 0
 阁 献: 0
 活 跃: 0
 发 贴: 12405 (0)
 阁 币: 24162  
性 别: I'm 火星人!
阅读权限: 90
在线时长: 0 小时
注册时间: 2016-10-16
最后登录: 2016-10-18
go
楼主
发表于 2016-10-17 16:25:27 |只看该作者 |倒序浏览
本帖发表于 2016-10-17 16:25:27...阅读 227 人...加油,亲爱的楼主:[db:作者]
上一篇我们涉及了面向对象的一个基本概念--封装,封装是一个相对比较简单的概念,也很容易接受,但是很多的场合下面,仅仅是封装并不能很好的解决很多问题,考虑下面的例子:
假设我们需要设计一个对战游戏的战斗细节,在最初的版本中我们将支持一种动作--fight。假设我们有三种角色:fighter、knight和warrior,每种角色的health、hit point不同,基于封装的基本想法,我们很自然的想到对每个对象使用类的封装,首先明显的元素有2个:health、hit point,另外还有name(我们不能只有三个角色)和战斗的速度speed,方法有:hit、isalive。基于这样的想法,我们给出下面的类:
class fighter
{
  private:
    int        m_iHealth;
    int       m_iSpeed;//为了方便,这个值使用延时值,越大表示速度越慢
    const int     m_iHitPoint;
    char       m_strName[260];
  public:
    fighter(const char* strName);
    void hit(fighter* pfighter);
    bool isAlive();
};
上面的类可以清楚的抽象出我们所需要表达的数据类型之一,这里也许你已经发现了一些问题:
成员函数hit用来处理战斗事件,但是我们有不同的角色,fighter不可能只跟自己同样的对手作战,我们希望它能和任何角色战斗,当然,使用模板函数可以简单的解决这个问题。另外,我们必须去实现三个不同的类,并且这些类必须都实现这些属性和方法。即使这些问题我们都解决了,现在我们要组织两个队伍作战,我们希望使用一种群体类型来描述它们,问题是我们必须针对每一种类建立相应的群体结构,当然你可以认为3个不同的类型不是很多,完全可以应付,那么如果有一天系统升级,你需要管理上百种类型的时候,会不会头大呢?
在C++中,继承就可以很好的解决这个问题,在C++中,继承表示的是一种IS-A关系,即派生类IS-A基类,很多现实世界中的关系可以这样来描述,如:dog is-a animal,dog是animal的派生(继承),继承产生的对象拥有父(基)对象的所有属性和行为,如animal的所有属性和行为在dog身上都会有相应的表现。在UML的描述中,这种关系被称为泛化(generalization)。一般情况下,当我们需要实现一系列相似(具有一定的共性)然而有彼此不同的类别的时候,使用继承都是很好的解决办法,例如前面的代码虽然也能够实现我们的目标,但是显然很难管理,下面给出使用继承后的实现:
class actor//基类
{
  protected:
    int        m_iHealth;
    const int     m_iSpeed;//为了方便,这个值使用延时值,越大表示速度越慢
    const int     m_iHitPoint;
    char       m_strName[260];
  public:
    actor(const char* strName,const int iHealth,const int iSpeed,const int iHitpoint);
    int& Health(){ return m_iHealth; };
    const char* getName(){ return m_strName; };
    virtual void hit(actor *Actor) = 0;
    bool isAlive();
}; 
actor::actor(const char* strName,const int iHealth,const int iSpeed,const int iHitpoint):
m_iHealth(iHealth),
m_iSpeed(iSpeed),
m_iHitPoint(iHitpoint)
{
  strcpy(m_strName,strName);
}
bool actor::isAlive()
{
  return (m_iHealth>0);
}
/////////////////////////////////////////////////////////
//类fighter
class fighter :public actor
{
  public:
    fighter(const char* strName);
    virtual void hit(actor *Actor);
  private:
};
fighter::fighter(const char* strName):
actor(strName,100,20,20)
{
}
void fighter::hit(actor *Actor)
{
  Sleep(m_iSpeed);
  if(!isAlive())
  {
    return ;
  }
  if(Actor&&Actor->isAlive())
  {
     //这里我们用一个函数做了左值,因为函数返回的是引用
    if(isAlive())
      Actor->Health() = Actor->Health() - m_iHitPoint;
  }
}
/////////////////////////////////////////////////////////
//类knight
class knight :public actor
{
  public:
    knight(const char* strName);
    virtual void hit(actor *Actor);
  private:
};
knight::knight(const char* strName):
actor(strName,150,20,25)
{
}
void knight::hit(actor *Actor)
{
  Sleep(m_iSpeed);
  if(!isAlive())
  {
    return ;
  }
  if(Actor&&Actor->isAlive())
  {
    if(isAlive())
      Actor->Health() = Actor->Health() - m_iHitPoint;
  }
}
/////////////////////////////////////////////////////////
//类warrior
class warrior :public actor
{
  public:
    warrior(const char* strName);
    virtual void hit(actor *Actor);
  private:
};
warrior::warrior(const char* strName):
actor(strName,150,20,25)
{
}
void warrior::hit(actor *Actor)
{
  Sleep(m_iSpeed);
  if(!isAlive())
  {
    return ;
  }
  if(Actor&&Actor->isAlive())
  {
    if(isAlive())
      Actor->Health() = Actor->Health() - m_iHitPoint;
  }
}
               
C++为我们提供了非常优秀的继承体系(其实这是面向对象的一个非常重要的特征),上面的类图中我们可以很清楚的看到他们的关系,在继承中,基类(有些地方也称为超类)其实是所有派生类的共性提炼的结果,有时候在开发过程中,是先有派生类,然后再提出共性,产生基类的。
就象遗传一样,派生类拥有基类的所有属性和方法,如基类actor的成员函数和成员变量在每一个派生类中都存在,即fighter、knight和warrior中都存在,在继承关系中还存在一个非常重要的关键字protected,它提供一个界于public和private 之间的一种可见性,与private相同的地方是对于外部来说,它不可见,与public相同的地方是对与继承体系来说,是向下可见的(其派生出来的类可以直接使用),这里有一点是很容易让人迷惑的,就是派生类中基类的成员可见性。对派生类来说,如果使用public继承,那么从基类中继承的所有成员的可见性不变(如果是protected继承,降一级,public变成protected,private继承再降),那么对于一个从基类继承来的private成员来说,派生类是无法访问的(很迷惑,是么?),虽然派生类含有这个变量,但是这是一种间接的拥有关系,在派生类中,含有一个基类的子对象,派生类对基类成员的访问正是通过这个子对象进行的。在思想中,永远不要把继承来的成员看做是自己真正拥有的,虽然使用this可以直接"看到"它们,在派生体系中private和public与其它情况没有任何区别,而protected在体系的内部就和public完全等同。
由于派生类拥有基类的成员,所以我们可以通过派生而简单的"重用"我们已有的代码,从而大大减少重复劳动。
关于继承的另外一个重要的特征就是虚函数,虚函数是形成类的多态的基础,在上面的类中:
void knight::hit(actor *Actor)
比如下面的伪码:
actor* pA;
knight* pKnight = new knight;
pA = pKnight;
pA->hit(…);
这里pA是一个基类的指针,而它指向的是一个派生类knight的指针,调用它应该是怎么样的情况呢?答案是hit会调用knight的方法,而不是基类的,因为它是一个虚函数,虚函数的特点是它永远忠实与实际的对象(前提是正确的使用),通过这种多态的特性,我们可以使用基类来对派生类进行正确的操作,这就解决了一个上面的问题:使用一种群体类型来描述它们,所以我们可以这样来遍历数据,而不需要关心里面究竟是一些什么样的数据:
vector troop1;
vector troop2;
vector::iterator it_tp1 = troop1.begin();
vector::iterator it_tp2 = troop2.begin();
while( (it_tp1!=troop1.end()) && (it_tp2!=troop2.end()) )
{
  while(((*it_tp1)->isAlive())&&(it_tp2!=troop2.end()))
  {
    (*it_tp1)->hit(*it_tp2);
    if(!(*it_tp2)->isAlive())
      it_tp2++;
  }
  it_tp1++;
}
面向对象思想中的继承是非常重要的概念,正确的运用它,会为软件的开发过程带来很多便利,同时,COM的核心技术是使用了多重继承来实现的。同时,继承也是面向对象的思想中较难理解的一个概念,这片文章我只能大致的讲述其运用,而真正的融会贯通还需要长时间的学习和实践。
下面我们给出上面的例子的完整代码,这段代码完成了随机建立两个队伍,并进行战斗,直到有一个队伍全军覆没,最后输出结果。
本文配套源码
分享到: QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏0 支持支持0 反对反对0

使用道具 举报

[至尊红钻3级]发帖数量≥1000篇 [至尊黄钻3级]威望≥500点 [至尊蓝钻1级]在线时间≥10小时 [至尊绿钻9级]贡献度≥80000点 [至尊紫钻9级]金币≥8000000个 [未点亮至尊粉钻]精华贴数不足10贴 [未点亮至尊黑钻]活跃不足8个
 等级: 
 级别: 管理员
 UID:  1   [未点亮普号显示]钻石不足3个
 阁 分: 2147483647
 阁 望: 993
 阁 献: 2147483647
 活 跃: 0
 发 贴: 1532 (0)
 阁 币: 9430326  
性 别: I'm 火星人!
阅读权限: 200
在线时长: 46 小时
注册时间: 2016-10-14
最后登录: 2023-10-3
沙发
发表于 2016-10-18 11:04:42 |只看该作者
本回复帖发表于 2016-10-18 11:04:42,感谢爱情孤儿对本帖的认真回复,你的回复是对楼主莫大的鼓舞
路过,学习下

使用道具 举报

[至尊红钻2级]发帖数量≥100篇 [未点亮至尊黄钻]威望不足10点 [未点亮至尊蓝钻]在线时间不足10小时 [未点亮至尊绿钻]贡献度不足10点 [未点亮至尊紫钻]金币不足100个 [未点亮至尊粉钻]精华贴数不足10贴 [未点亮至尊黑钻]活跃不足8个
 等级: 
 级别: 注册会员
 UID:  29   [未点亮普号显示]钻石不足3个
 阁 分: 111
 阁 望: 1
 阁 献: 4
 活 跃: 0
 发 贴: 104 (0)
 阁 币: 1  
性 别: I'm 火星人!
阅读权限: 20
在线时长: 2 小时
注册时间: 2011-1-6
最后登录: 2016-10-20
板凳
发表于 2016-10-19 20:19:11 |只看该作者
本回复帖发表于 2016-10-19 20:19:11,感谢za402对本帖的认真回复,你的回复是对楼主莫大的鼓舞
看帖回帖是美德!

使用道具 举报

高级模式
B Color Image Link Quote Code Smilies
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1、请认真发帖,禁止回复纯表情,纯数字等无意义的内容!帖子内容不要太简单!
2、提倡文明上网,净化网络环境!抵制低俗不良违法有害信息。
3、每个贴内连续回复请勿多余3贴,每个版面回复请勿多余10贴!
4、如果你对主帖作者的帖子不屑一顾的话,请勿回帖。谢谢合作!

手机版| 百度搜索:vkee.pw

2012-2015 卓航旗下 GMT+8, 2024-6-2 07:51 , Processed in 0.562125 second(s), 30 queries . Powered by Discuz! X3.2  

禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.如遇版权问题,请及时联系站长(QQ:5213513)

今天是: | 本站已经安全运行: //这个地方可以改颜色

快速回复 返回顶部 返回列表