2011-05-13 47 views
3

大家都說當至少有一個類方法是虛擬的時候析構函數應該是虛擬的。
我的問題是,使用上傳時,析構函數應該是虛擬的,是不是正確的?使用上傳時的虛擬析構函數

class A { 
public: 

    ~A(){ 
     cout << "Destructor in A" << endl; 
    } 
}; 

class B: public A 
{ 
public: 

    ~B(){ 
     cout << "Destructor in B" << endl; 
    } 
}; 

int main() 
{ 
    A* a = new B; 
    cout << "Exiting main" << endl; 
    delete a; 
} 

我沒有這段代碼中的虛函數,但是如果我不讓我的基礎析構函數變成虛擬的,它將不會調用B析構函數。是的,如果我沒有虛擬功能,我知道使用ucpasting是毫無意義的。

謝謝。

+0

你不是倒戈。 – 2011-05-13 12:47:06

+1

@尼爾:「A * a =新B」不是向上播放嗎? – 2011-05-13 12:56:58

+0

@Oli我在那裏看不到演員,是嗎? – 2011-05-13 12:57:40

回答

6

析構函數應該是虛擬時的類方法中的至少一個是虛擬

這是一個經驗法則,其源於這樣的事實,當你使用你正在使用運行時多態性虛函數,並更可能遇到的情況是你需要銷燬一個可能是派生類型的類,當你擁有的是一個指向其基類子對象的指針時。

當您通過在指向基類的指針上使用delete銷燬派生對象時,基類中需要虛擬析構函數以避免未定義的行爲。這是虛擬析構函數唯一需要的時間,並且該指南旨在幫助避免這種情況的發生。

Herb Sutter主張基類的析構函數(即析構設計成從繼承的類)的方針應該是publicvirtualprotected和非virtual。這使得您不希望基類成爲用於刪除派生對象的繼承層次結構中的一個點,並且您希望強制這不會無意中發生。

當然,如果你有一個純粹的值類不是基類,那麼你無法阻止從它派生出來的人,然後通過指向base的指針刪除派生類。

+0

+1我喜歡Herb Sutter的想法。我認爲他是對的 – Kobe 2011-05-13 13:16:28

+1

+1對於香草薩特的指導方針和一個很好的解釋。 – 2011-05-13 13:22:34

1

如果您要刪除指向派生類的指針,但是其中一個類方法是虛擬的,但是指針類型是基類,那麼在這種情況下,基類必須具有虛擬析構函數,否則應該總是聲明一個虛擬析構函數,或者編譯器不會(或不應該)知道它應該調用什麼析構函數(它是UB)。

+3

大多數人不會將_undefined behavior_看作是「完美無缺」的可接受示例。如果使用指向基類的指針「刪除」派生類而不考慮其他任何注意事項,則必須使用虛擬析構函數。 – 2011-05-13 12:46:54

+0

另外,什麼是「虛擬課堂」? – 2011-05-13 12:49:10

+0

@Charles:我試着更好地理解這個想法,是我正確編輯的內容嗎? @Neil Butterworth:Woops,我現在選擇了我的話:) – orlp 2011-05-13 12:52:34

1

如果你在派生類析構函數中做了一些有用的事情(內存釋放等),析構函數應該被製作爲virtual

順便說一句,這是建議(非強制)有虛析構函數時,class包含virtual方法。

+0

問題是,當你編寫基類時,你在技術上*不知道*派生類是否會做有用的事情。 – 2011-05-13 12:54:12

+0

@Andre,同意,但在這種情況下,總是析構函數將是虛擬的。瞭解其他派生析構函數在層次結構中所做的是一個好習慣。 – iammilind 2011-05-13 13:00:08

13

如果您通過基指針刪除派生對象,則需要虛擬析構函數。簡而言之,就是這樣。

+0

雖然這更準確,但提及的規則OP同樣適用,因爲如果基類沒有虛方法,則不太可能以這種方式刪除對象。 – 2011-05-13 12:53:13

+0

但是,如果你寫了一個庫,它可能不是你正在做的刪除,因此這種解釋是不夠的。您還需要了解爲什麼您可能通過指向基類的指針訪問對象(沒有該信息,這個答案不足以解釋這種情況)。 – 2011-05-13 13:16:25

0

這是不正確的:

shared_ptr<A> ptr = make_shared<B>(); 

做了演員和正確刪除B。只需按照@Neil Butterworth的回答。

相關問題