2008-12-09 50 views
44

Java和C#支持關鍵字finalsealed不能用作基類的類的概念。然而,在C++中,沒有什麼好方法可以防止從中派生出類,如果每個類都有虛擬析構函數,是否會讓類的作者左右爲難?每個班級都應該有一個虛擬析構函數嗎?


編輯:由於C++ 11這不再是真實的,你可以指定一個類是final


在一方面給予的對象的虛擬析構函數意味着它將具有vtable和因此消耗4(或8在64臺機器)每個對象的附加字節爲vptr

另一方面,如果稍後有人從此類派生並通過指向基類的指針刪除派生類,那麼程序將會不明確(由於沒有虛擬析構函數),並且坦率地針對每個對象的指針是荒謬的。

gripping hand有一個虛擬析構函數(可以說)宣傳這種類型意味着多態使用。

有些人認爲你需要明確的理由不使用虛擬析構函數(因爲是this question的潛臺詞),有人認爲只有當你有理由相信你的類是從派生的, 想什麼?

+0

已經有問題要求利弊 - 這是重複的,還是打算作爲民意調查?如果是後者,也許你應該爲投票創建「是」和「否」的答案,那麼結束這個問題呢?我認爲這是對SO執行多項選擇投票的推薦方式。 – 2008-12-09 19:01:55

+0

重複:http://stackoverflow.com/questions/270917/why-should-i-declare-a-virtual-destructor-for-an-abstract-class-in-c,http://stackoverflow.com/questions/300986 /當你不應該使用虛擬破壞者 – 2008-12-09 19:04:22

+6

「並坦率地爲每個對象的指針優化是荒謬的。」 - 它對於小對象並不可笑。 C++ 0x正在添加一個容器forward_list,這正是因爲有時每個對象的開銷太多 - 從空間和時間要求來看。 – 2008-12-09 19:23:55

回答

26

真正的問題是,你想執行你的類應該如何使用規則?爲什麼? 如果一個類沒有虛擬析構函數,那麼使用該類的任何人都知道它不是從派生而來的,並且如果您嘗試使用它,又會受到什麼限制。這不夠好嗎?

還是你需要編譯器拋出一個硬錯誤,如果有人dare做你沒有預料到的事情?

類提供一個虛析構函數,如果你打算讓人們從中獲得。否則不要,並且假定使用你的代碼的任何人都足夠聰明以正確使用你的代碼。

2

我會對一般問題「不」。不是類需要一個。如果你可以知道這個類不應該被繼承,那麼就沒有必要承擔小的開銷。但如果有機會,請保持安全並將其放在那裏。

8

不!虛擬析構函數僅在通過基類指針刪除派生類的對象時使用。如果你的類不打算在這種情況下作爲基礎,不要使析構函數虛擬 - 你會發送一個錯誤的信息。

+0

那麼你如何預測你的代碼有用的每一個實例?也許會有一些實例,其中你的類意味着你的非多態使用僅在某些特定的實例中作爲基類有用。 – v010dya 2016-06-27 05:34:10

53

每一個抽象類,要麼有,

  • 保護的析構函數,或者,
  • 虛析構函數。

如果你有一個公共的非虛擬析構函數,這是不好的,因爲它允許用戶通過該指針刪除一個派生對象。因爲我們都知道,這是未定義的行爲。

對於不打算通過指向它的指針進行刪除的類,沒有任何理由擁有虛擬析構函數。這不僅會浪費資源,更重要的是會給用戶一個錯誤的提示。試想一下,如果給std::iterator一個虛擬的析構函數,它會有多糟糕的感覺。

0

我會補充一點,有些時候,當我在父類或子類中忘記虛擬類時,有時會在析構函數中弄不清楚我的頭。我想我現在知道去尋找那個。:)

有人可能會說,有次在父類中做其析構函數,孩子不應該做的事情......但是這可能是出錯了繼承結構的指標無論如何。

0

基類成爲抽象類,當其含有至少一個純虛函數。如果Base沒有虛擬析構函數並且Derived(派生自Base),那麼可以通過派生對象指針安全地銷燬Derived對象,但不能通過Base對象指針。

-3
include<iostream> using namespace std; 

class base { 
    public: base() { 
     cout << "In base class constructor" << endl; 
    } 

    virtual ~base() { 
     cout << "in base class destuctor" << endl; 
    } 
}; 

class derived : public base { 
    public: derived() { 
     cout << "in derived class constructor" << endl; 
    } 

    ~derived() { 
     cout << "in derived class destructor" << endl; 
    } 
}; 

int main() { 
    base *b; // pointer to the base 
    class b = new derived; // creating the derived class object using new 
    keyword; 
    delete b; 
    return 0; 
} 
相關問題