條款 34:區(qū)分接口繼承和實現(xiàn)繼承(二)

Effective C++ 中文版 第三版》讀書筆記

這幾乎和前一個設(shè)計一模一樣,只不過 pure virtual 函數(shù) Airplane::fly 替換了獨立函數(shù) Airplane::defaultFly。其聲明部分表現(xiàn)表的是接口(derived class 必須使用的),其定義部分表現(xiàn)出缺省行為(那是 derived class 可能使用的,但只有在它們明確提出申請時才是)。合并 fly 和 defaultFly,就喪失了 “讓兩個函數(shù)享有不同保護級別” 的機會:習慣上被設(shè)為 protected 的函數(shù)(defaultFly)如今成了 public(因為它在 fly 之中)。

如果成員函數(shù)是個 non-virtual 函數(shù),意味著它并不打算在 derived classes 中有不同的行為。non-virtual 成員函數(shù)所表現(xiàn)的不變性凌駕其特異性,無論 derived class 變得多么特異化,它的行為都不可以改變。

聲明 non-virtual 函數(shù)的目的是為了令 derived class 繼承函數(shù)的接口及一份強制性實現(xiàn)。

來看 Shape::objectID 的聲明:可以想做是 “每個 Shape 對象都有一個用來產(chǎn)生對象識別碼的函數(shù):此識別碼總是采用相同計算方法,該方法由 Shape::objectID 的定義式?jīng)Q定,任何 derived class 都不應(yīng)該嘗試改變其行為”。

pure virtual 函數(shù)、simple(impure) virtual 函數(shù)、non-virtual 函數(shù)之間的差異,使你得以精確指定你想要 derived class 繼承的東西:只繼承接口,或是繼承接口和一份缺省實現(xiàn),或是繼承接口和一份強制實現(xiàn)。由于這些不同的類型的聲明意味著根本意義并不相同的事情,當你聲明你的成員函數(shù)時,必須謹慎選擇。如果你確實履行,應(yīng)該能夠避免經(jīng)驗不足的 class 設(shè)計者最常犯的兩個錯誤。

第一個錯誤是將所有的函數(shù)聲明為 non-virtual。這使得 derived class 沒有余裕的空間進行特化工作。non-virtual 析構(gòu)函數(shù)尤其會帶來問題。當然啦,設(shè)計一個并不相乘為基類的 class 是絕對合理的,既然這樣,將其所有成員函數(shù)都聲明為 non-virtual 也很適當。但這種聲明如果不是忽略了 virtual 和 non-virtual 之間的差異,就是過度擔心 virtual 函數(shù)的效率成本。實際上任何 class 如果打算被用來當做一個 base class,都會擁有若干 virtual 函數(shù)。

如果你關(guān)心 virtual 函數(shù)成本,可以了解一下 80-20 法則。這個法則說,一個典型的程序有 80% 的執(zhí)行時間花費在 20% 的代碼身上。此法則十分重要,因為它意味著,平均而言你的函數(shù)調(diào)用中可以有 80% 是 virtual 而不沖擊程序的大體效率。所以當你擔心是否有能力負擔 virtual 函數(shù)的成本之前,請先將心力放在那舉足輕重的 20% 代碼上頭,它才是真正的關(guān)鍵。

另一個常見錯誤是將所有函數(shù)都聲明為 virtual 函數(shù)。有時候這樣做是正確的,例如條款 31 的 interface class。然而這也可能是 class 設(shè)計者缺乏堅定立場的前兆。某些函數(shù)就是不該在 derived class 中被重新定義,果真如此你應(yīng)該將那些函數(shù)聲明為 non-virtual。沒有人有權(quán)利妄稱你的 class 適用于任何人任何事物而他們只需花點時間重新定義你的函數(shù)就可以享受一切。如果你的不變性凌駕于特異性,別害怕說出來。

請記?。?/p>

  1. 接口繼承和實現(xiàn)繼承不同。在 public 繼承下,derived class 總是繼承 base class 的接口。
  2. pure virtual 函數(shù)只具體制定接口繼承。
  3. 簡樸的(非純 impure)virtual 函數(shù)具體指定接口繼承及缺省實現(xiàn)繼承。
  4. non-virtual 函數(shù)具體制定接口繼承以及強制性實現(xiàn)繼承。
    這幾乎和前一個設(shè)計一模一樣,只不過 pure virtual 函數(shù) Airplane::fly 替換了獨立函數(shù) Airplane::defaultFly。其聲明部分表現(xiàn)表的是接口(derived class 必須使用的),其定義部分表現(xiàn)出缺省行為(那是 derived class 可能使用的,但只有在它們明確提出申請時才是)。合并 fly 和 defaultFly,就喪失了 “讓兩個函數(shù)享有不同保護級別” 的機會:習慣上被設(shè)為 protected 的函數(shù)(defaultFly)如今成了 public(因為它在 fly 之中)。

如果成員函數(shù)是個 non-virtual 函數(shù),意味著它并不打算在 derived classes 中有不同的行為。non-virtual 成員函數(shù)所表現(xiàn)的不變性凌駕其特異性,無論 derived class 變得多么特異化,它的行為都不可以改變。

聲明 non-virtual 函數(shù)的目的是為了令 derived class 繼承函數(shù)的接口及一份強制性實現(xiàn)。

來看 Shape::objectID 的聲明:可以想做是 “每個 Shape 對象都有一個用來產(chǎn)生對象識別碼的函數(shù):此識別碼總是采用相同計算方法,該方法由 Shape::objectID 的定義式?jīng)Q定,任何 derived class 都不應(yīng)該嘗試改變其行為”。

pure virtual 函數(shù)、simple(impure) virtual 函數(shù)、non-virtual 函數(shù)之間的差異,使你得以精確指定你想要 derived class 繼承的東西:只繼承接口,或是繼承接口和一份缺省實現(xiàn),或是繼承接口和一份強制實現(xiàn)。由于這些不同的類型的聲明意味著根本意義并不相同的事情,當你聲明你的成員函數(shù)時,必須謹慎選擇。如果你確實履行,應(yīng)該能夠避免經(jīng)驗不足的 class 設(shè)計者最常犯的兩個錯誤。

第一個錯誤是將所有的函數(shù)聲明為 non-virtual。這使得 derived class 沒有余裕的空間進行特化工作。non-virtual 析構(gòu)函數(shù)尤其會帶來問題。當然啦,設(shè)計一個并不相乘為基類的 class 是絕對合理的,既然這樣,將其所有成員函數(shù)都聲明為 non-virtual 也很適當。但這種聲明如果不是忽略了 virtual 和 non-virtual 之間的差異,就是過度擔心 virtual 函數(shù)的效率成本。實際上任何 class 如果打算被用來當做一個 base class,都會擁有若干 virtual 函數(shù)。

如果你關(guān)心 virtual 函數(shù)成本,可以了解一下 80-20 法則。這個法則說,一個典型的程序有 80% 的執(zhí)行時間花費在 20% 的代碼身上。此法則十分重要,因為它意味著,平均而言你的函數(shù)調(diào)用中可以有 80% 是 virtual 而不沖擊程序的大體效率。所以當你擔心是否有能力負擔 virtual 函數(shù)的成本之前,請先將心力放在那舉足輕重的 20% 代碼上頭,它才是真正的關(guān)鍵。

另一個常見錯誤是將所有函數(shù)都聲明為 virtual 函數(shù)。有時候這樣做是正確的,例如條款 31 的 interface class。然而這也可能是 class 設(shè)計者缺乏堅定立場的前兆。某些函數(shù)就是不該在 derived class 中被重新定義,果真如此你應(yīng)該將那些函數(shù)聲明為 non-virtual。沒有人有權(quán)利妄稱你的 class 適用于任何人任何事物而他們只需花點時間重新定義你的函數(shù)就可以享受一切。如果你的不變性凌駕于特異性,別害怕說出來。

請記住:

  1. 接口繼承和實現(xiàn)繼承不同。在 public 繼承下,derived class 總是繼承 base class 的接口。
  2. pure virtual 函數(shù)只具體制定接口繼承。
  3. 簡樸的(非純 impure)virtual 函數(shù)具體指定接口繼承及缺省實現(xiàn)繼承。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容