人人做人人澡人人爽欧美,国产主播一区二区,久久久精品五月天,羞羞视频在线观看免费

當前位置:蘿卜系統下載站 > 技術開發教程 > 詳細頁面

C++箴言:接口繼承與完成繼承

C++箴言:接口繼承與完成繼承

更新時間:2022-07-09 文章作者:未知 信息來源:網絡 閱讀次數:

(public) inheritance 這個表面上簡單易懂的觀念,一旦被近距離審視,就會被證明是由兩個相互獨立的部分組成的:inheritance of function interfaces(函數接口的繼承)和 inheritance of function implementations(函數實現的繼承)。這兩種 inheritance 之間的差異正好符合本書 Introduction 中論述的 function declarations(函數聲明)和 function definitions(函數定義)之間的差異。

  作為一個 class 的設計者,有的時候你想要 derived classes 只繼承一個 member function 的 interface (declaration)。有的時候你想要 derived classes 既繼承 interface(接口)也繼承 implementation(實現),但你要允許它們替換他們繼承到的 implementation。還有的時候你想要 derived classes 繼承一個函數的 interface(接口)和 implementation(實現),而不允許它們替換任何東西。

  為了更好地感覺這些選擇之間的不同之處,考慮一個在圖形應用程序中表示幾何圖形的 class hierarchy(類繼承體系):

  class Shape {
  public:
  virtual void draw() const = 0;

  virtual void error(const std::string& msg);

  int objectID() const;

  ...
  };

  class Rectangle: public Shape { ... };

  class Ellipse: public Shape { ... };

  Shape 是一個 abstract class(抽象類),它的 pure virtual function(純虛擬函數)表明了這一點。作為結果,客戶不能創建 Shape class 的實例,只能創建從它繼承的 classes 的實例。但是,Shape 對所有從它(公有)繼承的類施加了非常強大的影響,因為

  成員函數 interfaces are always inherited。就像 Item 32 解釋的,public inheritance 意味著 is-a,所以對一個 base class 來說成立的任何東西,對于它的 derived classes 也必須成立。因此,如果一個函數適用于一個 class,它也一定適用于它的 derived classes。

  Shape class 中聲明了三個函數。第一個,draw,在一個明確的顯示設備上畫出當前對象。第二個,error,如果 member functions 需要報告一個錯誤,就調用它。第三個,objectID,返回當前對象的唯一整型標識符。每一個函數都用不同的方式聲明:draw 是一個 pure virtual function(純虛擬函數);error 是一個 simple (impure?) virtual function(簡單虛擬函數);而 objectID 是一個 non-virtual function(非虛擬函數)。這些不同的聲明暗示了什么呢?

  考慮第一個 pure virtual function(純虛擬函數)draw:

  class Shape {
  public:
  virtual void draw() const = 0;
  ...
  };

  pure virtual functions(純虛擬函數)的兩個最顯著的特性是它們必須被任何繼承它們的具體類重新聲明,和抽象類中一般沒有它們的定義。把這兩個特性加在一起,你應該認識到。

  聲明一個 pure virtual function(純虛擬函數)的目的是使 derived classes 繼承一個函數 interface only。

  這就使 Shape::draw function 具有了完整的意義,因為它要求所有的 Shape 對象必須能夠畫出來是合情合理的,但是 Shape class 本身不能為這個函數提供一個合乎情理的缺省的實現。例如,畫一個橢圓的算法和畫一個矩形的算法是非常不同的,Shape::draw 的聲明告訴具體 derived classes 的設計者:“你必須提供一個 draw function,但是我對于你如何實現它不發表意見。”

  順便提一句,為一個 pure virtual function(純虛擬函數)提供一個定義是有可能的。也就是說,你可以為 Shape::draw 提供一個實現,而 C++ 也不會抱怨什么,但是調用它的唯一方法是用 class name 限定修飾這個調用:

  Shape *ps = new Shape; // error! Shape is abstract

  Shape *ps1 = new Rectangle; // fine
  ps1->draw(); // calls Rectangle::draw

  Shape *ps2 = new Ellipse; // fine
  ps2->draw(); // calls Ellipse::draw

  ps1->Shape::draw(); // calls Shape::draw

  ps2->Shape::draw(); // calls Shape::draw

  除了幫助你在雞尾酒會上給同行程序員留下印象外,這個特性通常沒什么用處,然而,就像下面你將看到的,它能用來作為一個“為 simple (impure) virtual functions 提供一個 safer-than-usual 的實現”的機制。

  simple virtual functions 背后的故事和 pure virtuals 有一點不同。derived classes 照常還是繼承函數的 interface,但是 simple virtual functions 提供了一個可以被 derived classes 替換的實現。如果你為此考慮一陣兒,你就會認識到

  聲明一個 simple virtual function 的目的是讓 derived classes 繼承一個函數 interface as well as a default implementation。

  考慮 Shape::error 的情況:

  class Shape {
  public:
  virtual void error(const std::string& msg);
  ...
  };

  interface 要求每一個 class 必須支持一個在遭遇到錯誤時被調用的函數,但是每一個 class 可以自由地用它覺得合適的任何方法處理錯誤。如果一個 class 不需要做什么特別的事情,它可以僅僅求助于 Shape class 中提供的錯誤處理的缺省版本。也就是說,Shape::error 的聲明告訴 derived classes 的設計者:“你應該支持一個 error function,但如果你不想自己寫,你可以求助 Shape class 中的缺省版本。”

  結果是:允許 simple virtual functions 既指定一個函數接口又指定一個缺省實現是危險的。來看一下為什么,考慮一個 XYZ 航空公司的飛機的 hierarchy(繼承體系)。XYZ 只有兩種飛機,Model A 和 Model B,它們都嚴格地按照同樣的方法飛行。于是,XYZ 設計如下 hierarchy(繼承體系):

  class Airport { ... }; // represents airports

  class Airplane {
  public:
  virtual void fly(const Airport& destination);

  ...

  };

  void Airplane::fly(const Airport& destination)
  {
  default code for flying an airplane to the given destination
  }

  class ModelA: public Airplane { ... };

  class ModelB: public Airplane { ... };

  為了表述所有的飛機必須支持一個 fly 函數,并為了“不同機型可能(在理論上)需要不同的對 fly 的實現”的事實,Airplane::fly 被聲明為 virtual。然而,為了避免在 ModelA 和 ModelB classes 中些重復的代碼,缺省的飛行行為由 Airplane::fly 的函數體提供,供 ModelA 和 ModelB 繼承。

  這是一個經典的 object-oriented 設計。因為兩個 classes 共享一個通用特性(它們實現 fly 的方法),所以這個通用特性就被轉移到一個 base class 之中,并由兩個 classes 來繼承這個特性。這個設計使得通用特性變得清楚明白,避免了代碼重復,提升了未來的可擴展性,簡化了長期的維護——因為 object-oriented 技術,所有這些東西都受到很高的追捧。XYZ 航空公司應該引以為榮。

  現在,假設 XYZ 公司的財富增長了,決定引進一種新機型,Model C。Model C 在某些方面與 Model A 和 Model B 不同。特別是,它的飛行不同。

  XYZ 公司的程序員在 hierarchy(繼承體系)中增加了 Model C 的 class,但是由于他們匆匆忙忙地讓新的機型投入服務,他們忘記了重定義 fly function:

  class ModelC: public Airplane {

  ... // no fly function is declared
  };

  于是,在他們的代碼中,就出現了類似這樣的東西:

  Airport PDX(...); // PDX is the airport near my home

  Airplane *pa = new ModelC;

  ...

  pa->fly(PDX); // calls Airplane::fly!

  這是一個災難:企圖讓一個 ModelC object 像一個 ModelA 或 ModelB 一樣飛行。這在旅行人群中可不是一種鼓舞人心的行為。

[1] [2]  下一頁

溫馨提示:喜歡本站的話,請收藏一下本站!

本類教程下載

系統下載排行

網站地圖xml | 網站地圖html
主站蜘蛛池模板: 银川市| 建始县| 广汉市| 蒙自县| 青阳县| 中宁县| 灌云县| 郯城县| 综艺| 唐海县| 武鸣县| 横峰县| 任丘市| 卓资县| 邻水| 舟山市| 乌兰察布市| 交口县| 盐亭县| 施秉县| 昌宁县| 双鸭山市| 都江堰市| 嘉鱼县| 巴青县| 和顺县| 兖州市| 仲巴县| 兴宁市| 郑州市| 岑巩县| 广平县| 谷城县| 新宁县| 紫阳县| 孝昌县| 原阳县| 博乐市| 阳春市| 新晃| 普陀区|