讀書筆記 Effective C

2022-03-01 14:18:01 字數 2204 閱讀 8559

嚴格來說,多型分為編譯時多型和執行時多型,編譯時多型是函式的過載,而執行時多型則是遲繫結技術,即根據基類指標或引用的實際指向來決定採取何種行動,一般來說,多型特指執行時多型。下面我們來舉有關c++多型的乙個簡單例子:

1

class

shape2;

8910class circle: public

shape

1116

};17

18class square: public

shape

1925 };

多型前提是繼承,如上面這個例子,shape是基類,它有乙個所有形狀都具有的屬性:顏色。circle和square派生自shape,它們都有顏色的屬性,但同時circle還有半徑的屬性,square有邊長的屬性。這裡print()函式是乙個有多型行為的函式,比如:

1 shape *p1 = new

square;

2 p1->print(); //

這時的執行結果就是「this is a square」

34 shape *p2 = new

circle;

5 p2->print(); //

這時的執行結果就是「this is a circle」

但這裡會有乙個問題,如果接下來操作:

delete p1;

delete p2;

就會出現記憶體的洩露,為什麼會這樣?因為shape沒有顯式定義析構函式,編譯器為我們生成的析構函式不是虛的,這時候delete p1,編譯器就簡單地析構了基類的部分,派生類的部分就被架空了,造成了記憶體的洩露。解決方法是這樣:

1

class

shape

28 };

有了virtual關鍵字,析構時就會檢查指標實際指向的物件,也就會先定位到相應的派生類,完成派生類的析構之後,再析構基類。那麼是怎麼「檢查」指標實際指向的物件呢?c++為每個含有virtual關鍵字的類中提供了乙個虛表指標vptr,它指向乙個由函式指標構成的陣列,稱為虛表。程式在執行時會維護類物件中的vptr,比如:

shape *p1 = new square;

vptr就會指向square的print()函式。

那是不是為了安全起見,將所有的析構函式都加上virtual呢?這樣的確可以防止多型過程中析構造成的記憶體洩露,但同時也有問題,即一旦出現了virtual,編譯器就會生成vptr,這個vptr本身是要佔空間的,對於乙個並不大的類而言,vptr所佔空間(32位機上是4位元組,64位機上是8位元組)的百分比還是很可觀的。所以virtual要相時而加,出現多型繼承關係時一定要加上,而非基類或者不用於多型的基類(比如條款6說的uncopyable)就不要加。另外,所有的stl,包括string,vector等等,在設計時就沒把它們當作基類,所以它們的析構函式都不是虛函式,因此試圖定義乙個類去繼承stl是非常危險的!

再回過頭來看之前的例子:

1

class

shape

28 };

注意到基類的print()函式不僅僅是虛的(含有virtual關鍵字),而且這個函式還是純虛函式(有「=0」),純虛函式所在的類是抽象類,是不能定義物件的,比如:

shape obj;

就不能通過編譯。使不想生成物件的類成為抽象類,這是乙個很好的技術實現方案,但萬一有時候難以找到乙個純虛函式,怎麼辦呢?自己強行加乙個像print()一樣的函式固然是可以的,但不自然,乙個好的方法是把它的析構函式變成純虛函式,像這樣:

1

class

shape

2;

問題算是解決一半了,還有乙個問題,編譯器會在shape派生類的析構函式中建立乙個對~shape()的呼叫動作,如果不實現這個~shape(),鏈結器會報錯,乙個解決方案就是簡單地加上括號,像這樣:

1

class

shape2;

7 };

好了,這下shape既成了抽象類(不能擁有物件),也能在繼承鏈中妥善地處理析構的記憶體問題。

總結一下:

(1)     帶有多型性質的基類應該宣告乙個virtual析構函式。如果class帶有任何virtual函式,它就應該擁有乙個virtual析構函式;

(2)     若乙個類不作為基類,或者不具備多型性(比如uncopyable),就不該宣告virtual析構函式。

《effective C 》讀書筆記

1,c 關鍵字explicit c 中,乙個引數的 建構函式 或者除了第乙個引數外其餘引數都有預設值的多參建構函式 承擔了兩個角色。1 是個 構造器,2 是個預設且隱含的型別轉換操作符 所以,有時候在我們寫下如 aaa 這樣的 且恰好 的型別正好是aaa單引數構造器的引數型別,這時候 編譯器就自動呼...

Effective C 讀書筆記

一 讓自己習慣c 1 條款01 視c 為聯邦語言 c 的組成可分為四部分 1.c c 仍然以c語言為基礎。區塊 語句 預處理 內建資料型別 陣列 指標等都來自c。2.object oriented c c with classes所訴說的 classes 包括構造和析構 封裝 繼承 多型 virtu...

讀書筆記 Effective C

部分條款過於深奧,部分條款已了然於心,僅記錄當下所識所學 對於常量巨集定義,最好用const代替 define 對於函式巨集定義,最好用inline代替 define include ifdef ifndef仍被需要 內建物件記得手動初始化 使用成員初始列替換賦值操作 以local static替換...