亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

C++箴言:接口繼承和實現繼承

2019-11-17 05:18:26
字體:
來源:轉載
供稿:網友
  (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 航空公司應該引以為榮?! ‖F在,假設 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 一樣飛行。這在旅行人群中可不是一種鼓舞人心的行為。

  這里的問題并不在于 Airplane::fly 有缺省的行為,而是在于 ModelC 被答應不必明確說出它要做什么就可以繼續這一行為。幸運的是,“為 derived classes(派生類)提供缺省的行為,但是除非它們提出明確的要求,否則就不交給他們”是很輕易做到的。這個訣竅就是切斷 virtual function(虛擬函數)的 interface(接口)和它的 default implementation(缺省實現)之間的聯系。以下用的就是這個方法:

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

...

protected:
void defaultFly(const Airport& destination);
};

void Airplane::defaultFly(const Airport& destination)
{
default code for flying an airplane to the given destination
}
  注重 Airplane::fly 是被如何變成一個 pure virtual function(純虛擬函數)的。它為飛行提供了 interface(接口)。那個缺省的實現也會出現在 Airplane class 中,但是現在它是一個獨立的函數,defaultFly。像 ModelA 和 ModelB 這樣需要使用缺省行為的 Classes 只是需要在他們的 fly 的函數體中做一下對 defaultFly 的 inline 調用(但是請參見 Item 30 提供的關于 inline 化和 virtual functions(虛擬函數)的交互作用的信息):

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

...
};

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

...
};
  對于 ModelC class,不可能在無意中繼續到不正確的 fly 的實現,因為 Airplane 中的 pure virtual(純虛擬)強制要求 ModelC 提供的它自己的 fly 版本。

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

...
};

void ModelC::fly(const Airport& destination)
{
code for flying a ModelC airplane to the given destination
}
  這一方案并非十分安全(程序員還是能通過 copy-and-paste 使他們自己陷入麻煩),但是它比最初的設計更加可靠。至于 Airplane::defaultFly,它是 protected(保護的)是因為它完全是 Airplane 和它的 derived classes(派生類)的實現細節。使用飛機的客戶應該只在意它能飛,而不必管飛行是如何實現的。

  Airplane::defaultFly 是一個 non-virtual function(非虛擬函數)這一點也很重要。這是因為 derived class(派生類)不應該重定義這個函數,這是一個在 Item 36 中專門介紹的原則。假如 defaultFly 是 virtual(虛擬的),你就會碰到一個循環的問題:假如某些 derived class(派生類)應該重定義 defaultFly 卻忘記了的時候會如何呢?

  一些人反對為 interface(接口)和 default implementation(缺省實現)分別提供函數,就像上面的 fly 和 defaultFly 那樣。首先,他們注重到,這樣做會導致類似的相關函數名污染 class namespace(類名字空間)的問題。然而他們仍然同意 interface(接口)和 default implementation(缺省實現)應該被分開。他們是怎樣解決這個表面上的矛盾呢?通過利用以下事實:pure virtual functions(純虛擬函數)必須在 concrete derived classes(具體派生類)中被 redeclared(重聲明),但是它們也可以有它們自己的實現。以下就是 Airplane hierarchy(繼續體系)如何利用這一能力定義一個 pure virtual function(純虛擬函數):


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

...
};

void Airplane::fly(const Airport& destination) // an implementation of
{ // a pure virtual function
default code for flying an airplane to
the given destination
}

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

...

};

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

...

};

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

...

};

void ModelC::fly(const Airport& destination)
{
code for flying a ModelC airplane to the given destination
}
  除了用 pure virtual function(純虛擬函數)Airplane::fly 的函數體代替了獨立函數 Airplane::defaultFly 之外,這是一個和前面的幾乎完全相同的設計。本質上,fly 可以被拆成兩個基本組件。它的 declaration(聲明)指定了它的 interface(接口)(這是 derived classes(派生類)必須使用的),而它的 definition(定義)指定它的缺省行為(這是 derived classes(派生類)可以使用的,但只是在他們明確要求這一點時)。將 fly 和 defaultFly 合并,無論如何,你失去了給予這兩個函數不同的保護層次的能力:原來是 protected 的代碼(通過位于 defaultFly 中實現)現在成為 public(因為它位于 fly 中)。

  最后,我們看看 Shape 的 non-virtual function(非虛擬函數),objectID:

class Shape {
public:
int objectID() const;
...
};
  當一個 member function(成員函數)是 non-virtual(非虛擬的)時,不應該指望它在 derived classes(派生類)中的行為會有所不同。實際上,一個 non-virtual member function(非虛擬成員函數)指定了一個 invariant over specialization(超越非凡化的不變量),因為不論一個 derived class(派生類)變得多么非凡,它都把它看作是不答應變化的行為。如下所指除的,

  聲明一個 non-virtual function(非虛擬函數)的目的是 to have derived classes inherit a function interface as well as a mandatory implementation(使派生類既繼續一個函數的接口,又繼續一個強制的實現)。

  你可以這樣考慮 Shape::objectID 的聲明,“每一個 Shape object 有一個產生 object identifier(對象標識碼),而且這個 object identifier(對象標識碼)總是用同樣的方法計算出來的,這個方法是由 Shape::objectID 的定義決定的,而且 derived class(派生類)不應該試圖改變它的做法?!币驗橐粋€ non-virtual function(非虛擬函數)被看作一個 invariant over specialization(超越非凡化的不變量),在 derived class(派生類)中他絕不應該被重定義,細節的討論參見 Item 36。

  對 pure virtual,simple virtual,和 non-virtual functions 的聲明的不同答應你精確指定你需要 derived classes(派生類)繼續什么東西。分別是 interface only(僅有接口),interface and a default implementation(接口和一個缺省的實現),和 interface and a mandatory implementation(接口和一個強制的實現)。因為這些不同的聲明類型意味著根本不同的意義,當你聲明你的 member functions(成員函數)時你必須在它們之間仔細地選擇。假如你這樣做了,你應該可以避免由缺乏經驗的類設計者造成的兩個最常見的錯誤。

  第一個錯誤是聲明所有的函數為 non-virtual(非虛擬)。這沒有給 derived classes(派生類)的非凡化留出空間;non-virtual destructors(非虛擬析構函數)尤其有問題(參見 Item 7)。當然,完全有理由設計一個不作為 base class(基類)使用的類。在這種情況下,一套獨享的 non-virtual member functions(非虛擬成員函數)是完全合理的。然而,更通常的情況下,這樣的類既可能出于對 virtual(虛擬)和 non-virtual functions(非虛擬函數)之間區別的無知,也可能是對 virtual functions(虛擬函數)的性能成本毫無根據的擔心的結果。事實是,幾乎任何作為 base class(基類)使用的類都會有 virtual functions(虛擬函數)(還是參見 Item 7)。

  假如你關心 virtual functions(虛擬函數)的成本,請答應我提起基于經驗的 80-20 規則(參見 Item 30),在一個典型的程序中的情況是,80% 的運行時間花費在執行其中的 20% 的代碼上。這個規則是很重要的,因為它意味著,平均下來,你的函數調用中的 80% 可以被虛擬化而不會對你的程序的整體性能產生哪怕是最稍微的可察覺的影響。在你走進對“你是否能負擔得起一個 virtual function(虛擬函數)的成本”憂慮的陰影之前,應該使用一些簡單的預防措施,以確保你關注的是你的程序中能產生決定性不同的那 20%。

  另一個常見的錯誤聲明所有的 member functions(成員函數)為 virtual(虛擬)。有時候這樣做是正確的—— Item 31 的 Interface classes(接口類)可以作為證據。然而,它也可能是缺乏表明態度的決心的類設計者的標志。某些函數在 derived classes(派生類)中不應該被重定義,而且只要在這種情況下,你都應該通過將那些函數聲明為 non-virtual(非虛擬)而明確地表達這一點。它不是為那些人服務的,他們假設假如他們只需花一些時間重定義你的所有函數,你的類就會被所有的人用來做所有的事情,假如你有一個 invariant over specialization(超越非凡化的不變量),請直說,不必害怕!

  Things to Remember

  ·Inheritance of interface(接口繼續)與 inheritance of implementation(實現繼續)不同。在 public inheritance(公開繼續)下,derived classes(派生類)總是繼續 base class interfaces(基類接口)。

  ·Pure virtual functions(純虛擬函數)指定 inheritance of interface only(僅有接口被繼續)。

  ·Simple (impure) virtual functions(簡單虛擬函數)指定 inheritance of interface(接口繼續)加上 inheritance of a default implementation(缺省實現繼續)。

  ·Non-virtual functions(非虛擬函數)指定 inheritance of interface(接口繼續)加上 inheritance of a mandatory implementation(強制實現繼續)。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩精品极品视频| 中文字幕亚洲一区在线观看| 日韩av在线一区二区| 日韩电影在线观看中文字幕| 日韩av在线电影网| 国产脚交av在线一区二区| 亚洲成人久久一区| 亚洲欧美中文另类| 美女av一区二区三区| 91九色国产在线| 亚洲香蕉伊综合在人在线视看| 欧美日韩亚洲天堂| 国产精品视频免费在线| 日韩视频免费观看| 精品一区二区三区电影| 国产伦精品一区二区三区精品视频| 国产日韩一区在线| 精品视频在线播放免| 国产精品成av人在线视午夜片| 亚洲美女在线视频| 国产日韩欧美一二三区| 色一区av在线| 欧美激情性做爰免费视频| 中日韩美女免费视频网站在线观看| 国产亚洲视频在线| 91国内产香蕉| 日韩视频在线观看免费| 国产精品久久99久久| 中文字幕精品www乱入免费视频| 欧美大片欧美激情性色a∨久久| 欧美激情免费观看| 欧美亚洲国产成人精品| 国产精品igao视频| 欧美丰满少妇xxxxx| 亚洲精选中文字幕| 日韩精品在线免费观看视频| 亚洲欧洲在线观看| 日韩在线观看网站| 精品久久久一区| 在线性视频日韩欧美| 黑人巨大精品欧美一区二区免费| 久久精品这里热有精品| 欧美孕妇性xx| 欧美日韩一区二区精品| 亚洲国产小视频在线观看| 日本精品久久久久久久| 国产精品丝袜高跟| 欧美激情成人在线视频| 日韩av影视在线| 国产一区二区三区免费视频| 国产精品极品尤物在线观看| 亚洲成人网在线| 少妇av一区二区三区| 国模叶桐国产精品一区| 亚洲欧美日韩国产成人| 欧美午夜精品久久久久久浪潮| 一区二区欧美亚洲| 一本色道久久综合狠狠躁篇怎么玩| 久久久国产成人精品| 91久久国产精品91久久性色| 91久久精品日日躁夜夜躁国产| 久久资源免费视频| 最近2019年手机中文字幕| 日韩精品电影网| 欧美日本高清视频| 992tv在线成人免费观看| 欧美午夜xxx| 久久久久久久久国产精品| 久久青草精品视频免费观看| 亚洲一区二区在线播放| 国产日韩欧美日韩大片| 精品一区二区三区四区在线| 这里只有精品在线观看| 欧美伊久线香蕉线新在线| 久久精品视频免费播放| 国产精品av在线播放| 亚洲一级片在线看| 国产精品入口免费视| 亚洲国产精品一区二区三区| 国产免费一区二区三区在线能观看| 日韩免费在线看| 九九久久久久久久久激情| 亚洲欧美资源在线| 久久久日本电影| 欧美日韩国产在线看| 日韩av中文字幕在线播放| 国产精品久久久久久久久久ktv| 最新国产精品亚洲| 国产精品欧美一区二区| 日韩激情第一页| 亚洲精品网站在线播放gif| 国产在线观看精品一区二区三区| 精品国产31久久久久久| 深夜福利日韩在线看| 一区二区三区无码高清视频| 亚洲国产精品大全| 亚洲精品久久久久久久久| 欧美视频二区36p| 九九久久国产精品| 亚洲欧美自拍一区| 久久精品免费播放| 久久免费福利视频| 中文字幕亚洲一区二区三区| 欧美性色19p| 亚洲国产天堂久久综合| 97免费视频在线播放| 一区二区国产精品视频| 国产美女精彩久久| 亚洲加勒比久久88色综合| 亚洲网站在线播放| 欧美激情中文字幕乱码免费| 国产乱肥老妇国产一区二| 国产成人在线视频| 国产精品一区二区电影| 国产日韩欧美综合| 日韩精品一区二区视频| 亚洲午夜激情免费视频| 91久久中文字幕| 国产精品久久激情| 欧美日韩不卡合集视频| 7777精品久久久久久| 国产精品www色诱视频| 欧美日韩一区二区在线播放| 亚洲欧美一区二区三区四区| 亚洲无限av看| 国产成人精品久久二区二区91| 欧美另类暴力丝袜| 黑人与娇小精品av专区| 亚洲精品一区二区在线| 亚洲日韩中文字幕在线播放| 91在线高清免费观看| 久久综合伊人77777| 亚洲高清在线观看| 日本欧美一二三区| 欧美亚洲在线视频| 国产精品激情av电影在线观看| 午夜精品久久久99热福利| 亚洲欧美制服另类日韩| 欧美性高跟鞋xxxxhd| 国产视频福利一区| 日本精品一区二区三区在线播放视频| 久热精品视频在线观看| 欧美多人爱爱视频网站| 欧美性生交大片免网| 国产精品视频久久久久| 亚洲欧美综合v| 日韩av在线免费观看一区| 精品亚洲夜色av98在线观看| 国产男人精品视频| 91牛牛免费视频| 国产区精品视频| 欧美精品少妇videofree| 日韩av电影免费观看高清| 国产一区二区成人| 麻豆国产精品va在线观看不卡| 久久69精品久久久久久国产越南| 欧美国产在线视频| 国产精品一区二区三| 国产精品69精品一区二区三区| 久久精品国产69国产精品亚洲| 亚洲欧洲日产国码av系列天堂| 亚洲**2019国产| 久久精品99久久久久久久久| 国产精品成av人在线视午夜片|