pure virtual destructors in c++




為什麼我應該在C++中聲明一個抽像類的虛析構函數? (5)

我知道在C ++中為基類聲明虛析構函數是一種很好的做法,但是對於聲明作為接口函數的抽像類的virtual析構函數總是很重要的? 請提供一些原因和示例。


你的問題的答案往往是,但並非總是如此。 如果你的抽像類禁止客戶在指向它的指針上調用delete(或者如果它在文檔中說明的話),你可以自由地不聲明虛擬析構函數。

您可以禁止客戶端通過使其析構函數受到保護來調用指向它的指針的delete。 像這樣工作,省略虛擬析構函數是完全安全合理的。

最終你最終將沒有虛擬方法表,並最終告訴你的客戶你有意通過指向它的指針使它不可刪除,所以你確實有理由不在這些情況下聲明它是虛擬的。

[見本文第4條: http://www.gotw.ca/publications/mill18.htmhttp://www.gotw.ca/publications/mill18.htm ]


凱文,首先,請不要在我們之前的討論中親自跳過你的評論,我不打算這麼苛刻。 無論如何,這個問題的主要答案。

這並不總是必需的,但我認為這是一個好習慣。 它的作用是允許派生對象通過基類型的指針安全地刪除。

例如:

Base *p = new Derived;
// use p as you see fit
delete p;

如果Base沒有虛擬析構函數,它就會形成格式,因為它會嘗試刪除該對象,就好像它是一個Base *


我決定做一些研究並嘗試總結你的答案。 下面的問題將幫助你決定你需要什麼樣的析構函數:

  1. 你的類是否打算用作基類?
    • 否:聲明公共的非虛擬析構函數以避免類的每個對像上的v指針*
    • 是的:閱讀下一個問題。
  2. 你的基類是抽象的嗎? (即任何虛擬純粹的方法?)
    • 否:嘗試通過重新設計類層次結構來使基類抽象化
    • 是的:閱讀下一個問題。
  3. 你想通過基指針來允許多態刪除嗎?
    • 否:聲明受保護的虛擬析構函數以防止不需要的使用。
    • 是的:聲明公共虛擬析構函數(在這種情況下沒有開銷)。

我希望這有幫助。

*重要的是要注意,在C ++中沒有辦法將類標記為final(即非子類),所以如果您決定將析構函數聲明為非虛擬的和公共的,請記得明確警告您的其他程序員反對從你的課堂派生出來。

參考文獻:


是的,它總是重要的。 派生類可以分配內存或保存對其他資源的引用,這些資源在對像被銷毀時將需要清理。 如果你不給你的接口/抽像類虛擬析構函數,那麼每次通過基類句柄刪除派生類實例時,派生類的析構函數將不會被調用。

因此,你正在開放內存洩漏的可能性

class IFoo
{
  public:
    virtual void DoFoo() = 0;
};

class Bar : public IFoo
{
  char* dooby = NULL;
  public:
    virtual void DoFoo() { dooby = new char[10]; }
    void ~Bar() { delete [] dooby; }
};

IFoo* baz = new Bar();
baz->DoFoo();
delete baz; // memory leak - dooby isn't deleted

這不僅是好的做法。 任何類層次結構都是規則1。

  1. C ++中最基本的層次結構必須具有虛擬析構函數

現在為什麼。 以典型的動物層次結構。 虛擬析構函數像其他任何方法調用一樣通過虛擬調度。 以下面的例子。

Animal* pAnimal = GetAnimal();
delete pAnimal;

假設動物是一個抽像類。 C ++知道正確的析構函數調用的唯一方法是通過虛擬方法調度。 如果析構函數不是虛擬的,那​​麼它將簡單地調用Animal的析構函數,而不銷毀派生類中的任何對象。

在基類中使析構函數虛擬的原因是它只是從派生類中刪除了選擇。 它們的析構函數默認為虛擬的。





virtual-destructor