[ 永遠的UNIX::UNIX技術資料的寶庫 ]   GB | BIG5

首頁 > 編程技術 > C/C++ > 正文
高質量C++/C編程指南 -- 第10章 類的繼承與組合
本文出自: 作者: 林銳 博士 (2002-07-25 06:02:00)

10 類的繼承與組合

 

對象(Object)是類(Class)的一個實例(Instance)。如果將對象比作房子,那類就是房子的設計圖紙。所以面向對象設計的重點是類的設計,而不是對象的設計。

C++程序而言,設計孤立的類是比較容易的,難的是正確設計基類及其派生類。本章僅僅論述“繼承”(Inheritance)和“組合”(Composition)的概念。

注意,當前面向對象技術的應用熱點是COMCORBA,這些內容超出了C++教材的范疇,請閱讀COMCORBA相關論。

10.1 繼承

如果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將自動具有Look SmellEatListen這些功能。示例10-2-2十分簡短並且運行正確,但是這種設計方法卻是不對的。

 

       // 功能正確並且代碼簡潔,但是設計方法不對。

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

{

};

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

 

一只公雞使勁地追打一只剛下了蛋的母雞,你知道為什嗎?

因為母雞下了鴨蛋。

很多程序員經不起“繼承”的誘惑而犯下設計錯誤。“運行正確”的程序不見得是高質量的程序,此處就是一個例証。

(http://www.fanqiang.com)
    進入【UNIX論壇

相關文章
高質量C++/C編程指南 -- 第9章 類的構造函數、析構函數與賦值函數 (2002-07-24 06:02:00)
高質量C++/C編程指南 -- 第8章 C++函數的高級特性 (2002-07-23 06:02:01)
高質量C++/C編程指南 -- 第7章 內存管理 (2) (2002-07-22 06:02:00)
高質量C++/C編程指南 -- 第7章 內存管理 (1) (2002-07-19 06:02:00)
高質量C++/C編程指南 -- 第6章 函數設計 (2002-07-18 06:02:00)
高質量C++/C編程指南 -- 第4章 表達式和基本語句 (2002-07-17 09:18:18)
高質量C++/C編程指南 -- 第5章 常量 (2002-07-17 06:02:00)
高質量C++/C編程指南 -- 第3章 命名規則 (2002-07-15 06:02:00)
高質量C++/C編程指南 -- 第2章 程序的版式 (2002-07-12 06:02:00)
高質量C++/C編程指南 -- 第1章 文件結構 (2002-07-11 06:02:01)

===更多相關===
 

★  樊強制作 歡迎分享  ★