C++编程规范---第10章 类的继承与组合

来源:互联网 发布:淘宝的旅游团怎么样 编辑:程序博客网 时间:2024/05/22 13:04

对象(Object)是类(Class)的一个实例(Instance)。如果将对象比作房子,那么类就是房子的设计图纸。所以面向对象设计的重点是类的设计,而不是对象的设计。

对于C++程序而言,设计孤立的类是比较容易的,难的是正确设计基类及其派生类。本章仅仅论述“继承”(Inheritance)和“组合”(Composition)的概念。

注意,当前面向对象技术的应用热点是COMCORBA,这些内容超出了C++教材的范畴,请阅读COMCORBA相关论著。

继承

如果A是基类,BA的派生类,那么B将继承A的数据和函数。例如:

       class A

{

  public:

              void  Func1(void);

              void  Func2(void);

};

 

class B : public A

{

  public:

              void  Func3(void);

              void  Func4(void);

};

 

       main()

{

              B  b;                   

              b.Func1();             // BA继承了函数Func1

              b.Func2();             // BA继承了函数Func2

              b.Func3();

              b.Func4();

}

 

这个简单的示例程序说明了一个事实:C++的“继承”特性可以提高程序的可复用性。正因为“继承”太有用、太容易用,才要防止乱用“继承”。我们应当给“继承”立一些使用规则。

 

l         【规则10-1-1如果类A和类B毫不相关,不可以为了使B的功能更多些而让B继承A的功能和属性。不要觉得“白吃白不吃”,让一个好端端的健壮青年无缘无故地吃人参补身体。

l         【规则10-1-2若在逻辑上BA的“一种”(a kind of ),则允许B继承A的功能和属性。例如男人(Man)是人(Human)的一种,男孩(Boy)是男人的一种。那么类Man可以从类Human派生,类Boy可以从类Man派生。

         class Human

{

                   …

};

         class Man : public Human

{

                   …

};

         class Boy : public Man

{

                   …

};

 

u       注意事项

【规则10-1-2看起来很简单,但是实际应用时可能会有意外,继承的概念在程序世界与现实世界并不完全相同。

例如从生物学角度讲,鸵鸟(Ostrich)是鸟(Bird)的一种,按理说类Ostrich应该可以从类Bird派生。但是鸵鸟不能飞,那么Ostrich::Fly是什么东西?

class Bird

{

public:    

       virtual void Fly(void);

};

 

class Ostrich : public Bird

{

};

 

例如从数学角度讲,圆(Circle)是一种特殊的椭圆(Ellipse),按理说类Circle应该可以从类Ellipse派生。但是椭圆有长轴和短轴,如果圆继承了椭圆的长轴和短轴,岂非画蛇添足?

       所以更加严格的继承规则应当是:若在逻辑上BA的“一种”,并且A的所有功能和属性对B而言都有意义,则允许B继承A的功能和属性。

10.2 组合

l         【规则10-2-1若在逻辑上AB的“一部分”(a part of),则不允许BA派生,而是要用A和其它东西组合出B

例如眼(Eye)、鼻(Nose)、口(Mouth)、耳(Ear)是头(Head)的一部分,所以类Head应该由类EyeNoseMouthEar组合而成,不是派生而成。如示例10-2-1所示。

 

class Eye

{
  public:

void  Look(void); 

};

class Nose

{
  public:

void  Smell(void);

};

class Mouth

{
  public:

void  Eat(void);    

};

class Ear

{
  public:

void  Listen(void);

};

// 正确的设计,虽然代码冗长。

class Head

{

  public:

              void       Look(void)     {  m_eye.Look();  }

              void       Smell(void)     {  m_nose.Smell();  }

              void       Eat(void) {  m_mouth.Eat();  }

              void       Listen(void)    {  m_ear.Listen();  }

  private:

              Eye       m_eye;

              Nose     m_nose;

              Mouth  m_mouth;

              Ear        m_ear;

};

示例10-2-1 HeadEyeNoseMouthEar组合而成

      

如果允许HeadEyeNoseMouthEar派生而成,那么Head将自动具有LookSmellEatListen这些功能。示例10-2-2十分简短并且运行正确,但是这种设计方法却是不对的。

 

       // 功能正确并且代码简洁,但是设计方法不对。

class Head : public Eye, public Nose, public Mouth, public Ear

{

};

示例10-2-2  HeadEyeNoseMouthEar派生而成

 

一只公鸡使劲地追打一只刚下了蛋的母鸡,你知道为什么吗?

因为母鸡下了鸭蛋。

很多程序员经不起“继承”的诱惑而犯下设计错误。“运行正确”的程序不见得是高质量的程序,此处就是一个例证。

 


原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 办不了健康证怎么办 办健康证不合格怎么办 美团健康证怎么办 便检取样很多怎么办 拉不出大便怎么办马上解决方法 无业人员怎么办健康证 健康证没身份证怎么办 身份证过期了怎么办护照 驾照体检表丢了怎么办 驾照体检表掉了怎么办 驾校体检表掉了怎么办 身份证掉了怎么办护照 驾照体检表过期了怎么办 助力车行驶证过期怎么办 c1证骑摩托车怎么办 别人知道驾驶证号码怎么办 摩托车卖了车牌怎么办 违章超过12分怎么办 违章扣分24分怎么办 驾驶证有效期过了怎么办 驾驶证到期没审怎么办 驾驶证扣不了分怎么办 集体户口怎么办户口本公证 强制保险单丢了怎么办 车子保险单丢了怎么办 汽车保险单子丢了怎么办 汽车保险贴丢了怎么办 保险本子丢了怎么办 平安保险单丢了怎么办 人寿保险单丢了怎么办 个人保险单丢了怎么办 学生保险单丢了怎么办 车保险单丢了怎么办 小孩保险单丢了怎么办 江苏省河道疏浚证怎么办 友利银行怎么办卡 专票信息没固话怎么办 廊坊市交警队放车后乱收费怎么办 驾驶本到期了怎么办 出国读研档案怎么办 出国留学 报到证怎么办