天天看點

Effective C++ 讀書筆記之Part6.Inheritance and Object-Oriented Design

32.Make sure public inheritance models "is-a".

所謂的最佳設計,取決于系統希望做什麼事,包括現在與未來。

需要解決的問題:其中關于兩個assert都通過的地方有些疑惑。

總結:

“public繼承”意味着is-a。适用于base classes身上的每一件事情一定也适用于derived classes身上,因為每一個derived class對象也都是一個base class對象。

33.Avoid hiding inherited names.

第一,derived classes内的名稱會遮掩base class内的名稱。在public繼承下從來沒有人希望如此。

第二,為了讓被遮掩的名稱再見天日,可使用using聲明式或轉交函數(forwarding functions)。

批注:

轉交函數就是在子類中的成員函數中跳轉到父類的成員函數。僅僅是加了一層包裝。

34. Differentiate between inheritance of interface and inheritance of implementation.

1)聲明一個pure virtual函數的目的是為了讓derived classes隻繼承函數接口。

2)聲明簡樸的(非純)impure virtual函數的目的,是讓derived classes繼承該函數的接口和預設實作。

3)聲明non-virtual函數的目的是為了令derived classes繼承函數的接口及一份強制性實作。

第一,接口繼承和實作繼承不同。在public繼承之下,derived classes總是繼承base class的接口。

第二,pure virtual 函數隻具體制定接口繼承。

第三,簡樸的(非純)impure virtual函數具體指定接口繼承及預設實作繼承。

第四,non-virtual函數具體制定接口繼承以及強制性實作繼承。

35.Consider alternatives to virtual functions.

令客戶通過public non-virtual成員函數間接調用private virtual函數,稱為non-virtual interface(NVI)手法。它是所謂Template Method設計模式(與C++ templates并無關聯)的一個獨特表現形式。

1)使用non-virtual interface(NVI)手法,那是Template Method設計模式的一種特殊形式。它以public non-virtual 成員函數包裹較低通路性(private或protected)的virtual函數。

2)将virtual函數替換為“函數指針成員變量”,這是Strategy設計模式的一種分解表現形式。

3)以tr1::function成員變量替換virtual函數,因而允許使用任何可調用物(callable entity)搭配一個相容于需求的簽名式。這也是Strategy設計模式的某種形式。

4)将繼承體系内的virtual函數替換為另一個繼承體系内的virtual函數。這是Strategy設計模式的傳統實作手法。

第一,virtual函數的替代方案包括NVI手法及Strategy設計模式的多種形式。NVI手法自身是一個特殊形式的Template Method設計模式。

第二,将機能從成員函數移到class外部函數,帶來的一個缺點是,非成員函數無法通路class的non-public成員。

第三,tr1::function對象的行為就像一般函數指針。這樣的對象可接納“與給定之目标簽名式(target signature)相容”的所有可調用物(callable entities)。

批注:該條款主要介紹了針對virtual函數實作功能的集中實作方式,主要是分為兩個方面,一個方面是NVI,一個方面是設計模式中的Strategy的幾種實作方式。

36. Never redefine an inherited non-virtual function.

絕對不要重新定義繼承而來的non-virtual函數。

主要是因為如果你這麼做了,首先,你破壞了non-virtual函數應該被完全繼承的初衷;其次,這樣做會導緻混亂。是以這是一個不合理的情況,要不聲明為virtual,要不就不要重新定義。否則這樣帶來的混亂是對象執行成員函數的時候,取決于它們的聲明類型,而不是本身自己所指向的類型。

37. Never redefine a functions's inherited default parameter value.

對象的所謂靜态類型(static type),就是它在程式中被聲明時所采用的類型。

對象的所謂動态類型(dynamic type),就是指“目前所指對象的類型”。

絕對不要重新定義一個繼承而來的預設參數數值,因為預設參數數值都是靜态綁定,而virtual函數---你唯一應該覆寫的東西---卻是動态綁定。

由此可見很大一部分問題都是由于動态綁定和靜态綁定的原因造成的。由此可類推到virtual函數以及non-virtual函數。

38. Model "has-a" or "is-implemented-in-terms-of" through composition.

第一,複合(composition)的意義和public繼承完全不同。

第二,在應用域(application domain),複合意味着has-a(有一個)。在實作域(implementation domain),複合意味is-implemented-in-terms-of(根據某物實作出)。

39. Use private inheritance judiciously.

複合和private繼承都意味is-implemented-in-terms-of,但複合比較容易了解,是以無論什麼時候,隻要可以,你還是應該選擇複合。

第一,private繼承意味is-implemented-in-term-of(根據某物實作出)。它通常比複合(composition)的級别低。但是當derived class需要通路protected base class的成員,或需要重新定義繼承而來的virtual函數時,這麼設計是合理的。

第二,和複合(composition)不同,private繼承可以造成empty base最優化。這對緻力于“對象尺寸最小化”的程式庫開發者而言,可能很重要。

主要關注了private繼承下的情況。

40. Use multiple inheritance judiciously.

第一,多重繼承比單一繼承複雜。它可能導緻新的歧義性,以及對virtual繼承的需要。

第二,virtual繼承會增加大小、速度、初始化(及指派)複雜度等等成本。如果virtual base class不帶任何資料,将是最具實用價值的情況。

第三,多重繼承的确有正當用途。其中一個情節涉及“public繼承某個Interface class”和“private繼承某個協助實作的class”的兩組結合。

繼續閱讀