#includeusingcbird作為基類描述鳥類的一般行為和屬性,因為不同鳥類的飛行特點不同,所以基類cbird將fly()宣告為virtrual,希望派生類重寫(overriding)該方法。clark(lark:百靈鳥)繼承自cbird,並重寫了fly()。namespace
std;
class
cbird
; ~cbird() ;
virtual
void fly() ;
};class clark : public
cbird
; ~clark() ;
void fly()
};int
main()
main函式中基類cbird型別指標指向派生類clark型別物件,並以基類指標呼叫fly方法,根據c++的多型特性,實際呼叫的是clark的fly方法。
可以看到「pbird->fly();」的確呼叫了派生類clark的fly方法。但物件析構時只呼叫了基類cbird的析構函式,卻沒有呼叫派生類clark的析構函式,這種現象叫做「部分析構」。
產生這個問題的原因是:當乙個派生類物件通過乙個基類指標刪除,並且這個基類的析構函式是非虛的,
c++將不會呼叫整個析構函式鏈,結果是未定義的。
所以這種情況下,只呼叫了基類cbird的析構函式,物件的派生部分並沒有被銷毀。
解決辦法就是將多型基類的析構函式設定為virtual。多型基類指的是基類中至少存在乙個virtual函式,具有virtual函式的類也就是想當爹(base class)的類,這樣的類簡稱為多型基類。將cbird的析構函式設定為virtual,再看程式的輸出結果。
並不是所有c++類都應該將析構函式設定為virtual。只有具有
virtual
函式的多型基類(或者其它想當
base class
的類)才應該將析構函式設定為
virtual
,對於普通的類則無必要。
因為虛函式的實現要求物件攜帶額外資訊,也就是維護乙個指向虛函式表的指標vptr(virtual table pointer),vptr指向虛函式表vtbl(virtual table)。當呼叫乙個物件的虛函式時,就會通過vptr找到vtbl,在vtbl中尋找正確的函式指標呼叫。由於vptr的加入,導致物件大小增加。所以對於非多型基類,沒必要將析構函式宣告為virtual以帶來額外負擔。這同時引出另外一條準則,如果乙個類的析構函式非虛,那就說明它不想當爹,程式設計師要頂住**,拒絕繼承它,即使它「出身名門」,比如標準庫中的string等等。
另外,有時還會將析構函式設定為純虛函式(pure virtual),擁有純虛函式的類變為抽象基類(abstract class),抽象基類不能被例項化。如果某個class只希望作為base class(不希望被例項化),但是又沒有乙個純虛函式,而base class應該有乙個virtual析構函式,那麼此時就可以將析構函式設定為純虛函式。
必須為純虛析構函式提供定義,否則會出現link錯誤。因為析構函式的運作方式是,最深層派生(most derived)的那個class其析構函式最先被呼叫。然後是其每乙個base class的析構函式被呼叫。
【學習資料】 《effective c++》 《編寫高質量** c++》
多型基類的析構函式應該為虛函式
includeusing namespace std class cbird cbird virtual void fly class clark public cbird clark void fly int main cbird作為基類描述鳥類的一般行為和屬性,因為不同鳥類的飛行特點不同,所以基...
多型基類與虛析構函式
假設我們有乙個基類a,很不幸的,a的析構函式是乙個non virtual。同時我們有乙個派生類b,它派生自a。我們定義了乙個a型別指標,它指向的實際物件是b a ptr new b 然後在程式的某處,我們不再需要b了,我們將指標ptr delete掉 delete ptr 注意new永遠要和dele...
建構函式和析構函式是否應該為虛函式
建構函式不能是虛函式。因為建立派生類的物件時,將呼叫派生類的建構函式,而不是基類的建構函式,然後,派生類的建構函式將使用基類的乙個建構函式,這種順序不同於繼承機制。因此,派生類不繼承基類的建構函式,所以將類建構函式宣告為虛的沒什麼意義。析構函式應該是虛函式,除非類不用做基類。例如當e為基類,s是派生...