條款7 為多型基類宣告virtual析構函式

2022-04-10 12:59:42 字數 2310 閱讀 2889

現在需要一種設計,要設計乙個類記錄時間,但是記錄時間的方式有很多,可以通過手機mobileclock,可以通過水鐘waterclock等。

所以要這種實現的方式:

class timekeeper

;class mobileclock : public timekeeper

;class waterclock : public timekeeper

;

這種設計的方式是工廠factory的方式,利用了c++多型的方式。利用父類的指標timekeeper*指向任何子類的物件就可以實現了,這樣的方式很容易維護和功能的擴充套件。比如有一天我想擴充套件計時的方式,我想用原子鐘計時,增加乙個atomicclock類,利用這種設計能改動最少的**實現功能的擴充套件。

所以工廠函式是這樣的:

timekeeper *ptk = gettimekeeper();

被gettimekeeper返回的這個物件應該位於記憶體的heap儲存區,為了避免記憶體洩露,程式必須將factory返回的每乙個物件在合適的時候用delete釋放掉。

所以**是這樣的:

timekeeper *ptk = gettimekeeper();

//todo:這裡用ptk做一些操作,比如顯示時間等

delete ptk;

這樣的操作表面上看似乎有點合理,但是我們會發現在通過釋放delete物件的時候,基類指標ptk要呼叫乙個析構函式。又由於基類(timekeeper)的析構函式是non-virtual的,是靜態繫結的。所以這裡通過ptk指標呼叫的是基類timekeeper的析構函式。那麼這個基類的析構函式能把整個派生類物件釋放掉嗎?答案是不能。它只能釋放派生類物件中的基類的成分,並不能釋放專屬於派生類的那部分空間。於是就造成了乙個詭異的「區域性銷毀」物件。

解決這個問題的方法很簡單:把基類的析構函式做成virtual的,這樣的話通過基類的指標ptk呼叫乙個析構函式的時候,就會動態繫結,根據ptk實際指向的物件呼叫這個物件的析構函式。這樣就自動的呼叫到了派生類的析構函式。通過派生類的析構函式就能如願的釋放掉派生類物件,同時也能夠釋放掉基類的成分

class timekeeper

;

注意這裡說的為析構函式增加virtual關鍵字針對的是多型基類而言的。這種類都是用來派生用的,同時還會有其他的virtual函式,如virtual getcurrenttime,然後在不同的派生類中在定製它們自己的getcurrenttime。所以總而言之,任何用作多型基類的class都會有一些virtual的函式,這時為這個多型基類定義乙個virtual的析構函式是很必要的。

多型基類和virtual函式是一起出現的,乙個類只要有virtual函式,那麼這個類一定是要打算作為多型基類使用的,所以要有乙個virtual的析構函式。換而言之,如果乙個類是作為多型基類設計的,那麼它至少有乙個virtual函式,那麼這時析構函式也要宣告為virtual。

所以這一條的規則是為多型基類宣告乙個virtual的析構函式。但是反過來,如果乙個庫檔案中的類並沒有設計成基類的意圖,千萬不要去繼承它,不然當你對這個基類使用多型的時候,就會發生上面的「物件區域性銷毀」的現象發生。(因為你不能修改乙個庫檔案中的類)

考慮乙個二維空間的座標點的class:

class point

;

這樣的類在設計的時候都沒有把他當做基類的意圖,你如果硬是要給它的析構函式加上乙個virtual,那麼這個class的例項就會占用更多的空間,因為除了兩個int變數外,還有在物件的開始的部分存放該物件的虛函式表的指標,表明這個物件的虛函式表在記憶體的位址。這樣的話如果把這個類給c語言或者其他語言,大小就會不對應,除非明確的補償虛函式表指標占用的空間,才能具有移植性。

所以,對於那些非多型基類的類,不要把其析構函式宣告為virtual的。

並非所有的基類的設計目的都是為了多型用途,例如標準string和stl容器都不被設計作為基類使用,更別提多型了。某些class的設計目的是作為基類使用,但不是為了多型,它們並不需要「父類的指標指向子類的物件」做一些操作。所以也不需要宣告virtual的析構函式。

上面的規則其實很簡單:

為多型基類宣告乙個virtual的析構函式。

如果乙個類不是用作基類的用途,不要把它的析構函式宣告為virtual;

如果乙個類是作為基類的用途,同時需要「父類的指標指向子類的物件」做一些操作,那麼要宣告乙個virtual的析構函式;

如果乙個類是作為基類的用途,但是不需要多型操作子類物件,不要宣告乙個virtual的析構函式。

最後一句:多型基類和virtual函式是一起出現的,誰離開了誰都玩不了。

條款7 為多型基類析構函式宣告為virtual

基類指標指向子類物件。子類物件必須位於堆。因此為了避免洩漏記憶體資源,當指標不使用時,delete掉每乙個物件非常重要。但是如果基類的析構函式不宣告為virtual。那麼指向子類物件的指標delete時,析構掉的成分都是基類的,而子類的成分沒有被識別出來,而未被析構掉。這樣就造成資源浪費。給基類析構...

條款7 為多型基類宣告virtual析構函式

1.將析構函式宣告為virtual 當我們的類要作為基類的時候我們最好將其析構函式宣告為virtual型別,因為當我們用基類的指標指向乙個派生類,當我們要用基類指標析構掉這個派生類的時候,如果基類的析構函式不是virtual,那麼最終只有基類裡面宣告的變數被析構掉,而派生類裡面的變數很可能沒被析構掉...

條款7 為多型基類 宣告virtual析構函式

1 c 明確指出,當派生類物件經由乙個base class指標被刪除,而該base class帶著乙個non virtual析構函式,其結果未有定義 實際執行時通常發生得是子類物件得derived成分沒有被銷毀,消除這個問題得做法很簡單,給base類乙個虛擬構函式,此後刪除派生類物件就會如你想要得那...