1.[effective c++原則07]:為多型基類宣告virtual 析構函式。
[如果不]: 如果不宣告為析構函式,可能出現的結果如下:derived物件的成分沒有被銷毀,形成資源洩露、在除錯上會浪費很長時間。
#include
using namespace std;
class
c******class
~c******class()
private:}
;class
cderived
:public c******class
~cderived()
private:}
;int
main()
執行結果如下:
顯然,cderived
物件沒有被析構!
1、 造成上述不同的原因何在?
「c++標準」明確指出,當派生類物件經由乙個基類指標pbaseobject被刪除,而該基類帶有乙個non-virtual析構函式,其結果未有定義(即不可預知)。實際執行時,如上面第乙個圖示,會產生bug,派生類的物件沒有被銷毀。
這就形成詭異的「區域性銷毀」物件,形成資源洩露。
2、 什麼時候需要基類析構函式宣告為虛函式?
什麼時候不需要基類的析構函式為虛函式?
該問題涉及析構函式何時應該為虛函式。注意:對於上面的基類baseclass,
若析構函式不為虛函式,sizeof(baseclass) = 1。
若析構函式為虛函式,sizeof(baseclass) = 4。
至於為什麼包含建構函式、非虛析構函式的類的大小為1個位元組。解釋如下:
空類類的大小比如baseclass沒有構造、析構函式,本來sizeof(baseclass)應該為0,但是我們宣告該型別例項的時候,必須在記憶體中占用一定的空間,否則無法使用這些例項。至於占用多少記憶體,由編譯器決定,visual studio中每個空型別的例項占用1個位元組的空間。
而加上建構函式、析構函式或其他非虛型別的函式以後呢?由於這些非虛型別的函式的位址只與類有關,而與類的例項無關,編譯器不會因為非虛函式的增加而新增任何額外的資訊。
那麼為什麼析構函式變成虛函式後,大小就變成4個位元組了呢?主要原因是:c++一旦發現類中有虛函式,就會為該類生成虛函式表,並在該型別的每乙個例項中新增指向虛函式表的指標。在32位機器上,乙個指標佔4個位元組的空間,所以求sizeof大小為4。而在64位機器上,乙個指標占用8個位元組的空間,因此sizeof大小為8。
即為類析構函式宣告為虛析構函式是以付出記憶體為代價的。所以,無端將所有類的析構函式宣告為虛函式,就向從未宣告它們是虛函式一樣,都是錯誤的。
總結如下:
(1)帶多型性質的基類應用宣告乙個虛析構函式。如果類中帶有任何虛函式,它就應該擁有乙個虛析構函式;
(2)設計類的目的如果不作為基類,或者不是為了具備多型性,就不應該宣告虛析構函式。
——參考《effective c++》條款7;《劍指offer》
2.[effective 原則09]:絕不在構造和析構過程中呼叫virtual函式。
【原因】:base class的執行更早於derived class的建構函式,當base class的建構函式執行的時候derived class的成員變數尚未初始化。
【如果不】:執行的結果不會動態聯編,依然執行其所在層的虛函式。
3.綜合1,2的筆試題如下:
#include
using namespace std;
class cbase
//呼叫本層的foo
~cbase()
//未加virtual,且呼叫本層的foo
顯然,1.cderived的析構函式不會被呼叫,因為cbase的析構函式非虛函式。
2.在cbase的構造和析構函式中呼叫虛函式,僅會執行本層的定義,不會下調。還是遵照[effective 原則09]:絕不在構造和析構過程中呼叫virtual函式為上策。
C 虛析構函式 純虛析構函式
虛析構函式 析構函式的工作方式是 最底層的派生類 most derived class 的析構函式最先被呼叫,然後呼叫每乙個基類的析構函式。因為在c 中,當乙個派生類物件通過使用乙個基類指標刪除,而這個基類有乙個非虛的析構函式,則結果是未定義的。執行時比較有代表性的後果是物件的派生部分不會被銷毀。然...
C 虛析構函式 純虛析構函式
虛析構函式 析構函式的工作方式是 最底層的派生類 most derived class 的析構函式最先被呼叫,然後呼叫每乙個基類的析構函式。因為在c 中,當乙個派生類物件通過使用乙個基類指標刪除,而這個基類有乙個非虛的析構函式,則結果是未定義的。執行時比較有代表性的後果是物件的派生部分不會被銷毀。然...
C 虛析構函式 純虛析構函式
虛析構函式 析構函式的工作方式是 最底層的派生類 most derived class 的析構函式最先被呼叫,然後呼叫每乙個基類的析構函式。因為在c 中,當乙個派生類物件通過使用乙個基類指標刪除,而這個基類有乙個非虛的析構函式,則結果是未定義的。執行時比較有代表性的後果是物件的派生部分不會被銷毀。然...