2012-01-07 91 views
4

我已經編寫了使用三種類型的此測試代碼:struct One是一個沒有虛擬成員的普通類型,struct Two : One有一個純虛函數和一個虛析構函數,並且struct Three : Two實現Two的接口。從非虛擬父類虛擬類繼承的正確方式

#include <iostream> 

struct One 
{ 
    ~One() { 
     std::cout << "~One()\n"; 
    } 
}; 

struct Two : One 
{ 
    virtual ~Two() { 
     std::cout << "~Two()\n"; 
    } 

    virtual void test() = 0; 
}; 

struct Three : Two 
{ 
    virtual ~Three() { 
     std::cout << "~Three()\n"; 
    } 

    virtual void test() { 
     std::cout << "Three::test()\n"; 
    } 
}; 

int main() 
{ 
    Two* two = new Three; 
    two->test(); 

    One* one = two; 
    delete one; 
} 

不出所料,the output was此:

三個::測試()
〜一()

有沒有什麼辦法比讓每一個虛擬析構函數來解決這個其他?或者程序員是否應該小心不要陷入這種情況?我覺得奇怪,編譯時沒有警告。

+0

一個簡單的解決方法:使用來自'One'的私有或受保護的繼承,並通過聲明公開功能。 – Xeo 2012-01-07 11:39:51

回答

2

唯一的「修復」不是通過指向One的指針來刪除對象。

如果這是一個常見問題,取決於您的類如何使用。例如,標準庫包含像unary_function這樣的結構,沒有虛擬析構函數,但我們很少看到它像這樣被濫用。

+0

並強制執行,應該保護'One'的析構函數 – 2012-01-07 11:34:53

1

你一定要小心,使虛擬的析構函數。有些編譯器會對此提出警告。

1

如果你想在派生類中使用析構函數,那麼你必須將它們定義爲虛擬的。這是唯一的方法。

2

delete one調用未定義的行爲,因爲對象的動態類型與靜態類型不匹配,並且靜態類型沒有虛擬析構函數。

避免這種問題的常用方法是使析構函數成爲public和virtual,或者protected和non-virtual(在預期以這種方式使用的類上)。