2017-05-10 75 views
-1

當我試圖刪除導出的對象多態(即:基類有公共虛擬析構函數)爲什麼派生類私人析構函數仍被調用?爲什麼範圍決議私人不在這裏工作。Private Derived Destructor

class Base 
{ 
protected: 
    Base() { cout << "Base constructor.\n"; } 
public: 
    virtual ~Base() { cout << "Base destructor.\n"; } 
}; 

class Derived :public Base 
{ 
public: 
    Derived() { cout << "Derived constructor.\n"; } 
private: 
    ~Derived() { cout << "Derived destructor.\n"; } 
}; 

int main() 
{ 
    Base *p = new Derived(); 
    delete p; 
} 

輸出:

Base constructor. 
Derived constructor. 
Derived destructor. 
Base destructor. 
+1

因爲您通過基類指針調用派生的dtor ... –

回答

3

由於析構函數按構造函數的相反順序調用,並且虛擬析構函數將始終被調用。

private如果要調用虛擬函數沒有任何關係。

正如我指出這裏走出來的:

Why would a virtual function be private?

ISO C++標準1998年起明確規定:

10.3節[...]訪問控制(第11條)不考慮確定重寫。


有點哲學offtopic:

進一步說這是STL確實爲iostreams:中Non-Virtual Interface定義,即所有的公共功能(與析構函數的除外)都是非虛,所有的虛函數是protectedprivate。公共函數調用虛擬保護或私有函數。這給整個層次結構提供了一個非常明確的切入點。

1

它,但你不能直接調用~Derived()。如果你要使用

Derived *p = new Derived(); 
delete p; 

那麼你會得到的錯誤。但是,當您通過多態性間接訪問~Derived()(例如,通過調用~Base()),則訪問說明符private不適用。

根據[class.access.virt#1]

通過其聲明確定,並且不受該後來覆蓋它的功能的規則的訪問規則(第[class.access])爲虛擬功能。 [實施例:

class B { 
public: 
    virtual int f(); 
}; 

class D : public B { 
private: 
    int f(); 
}; 

void f() { 
    D d; 
    B* pb = &d; 
    D* pd = &d; 

    pb->f();      // OK: B​::​f() is public, D​::​f() is invoked 
    pd->f();      // error: D​::​f() is private 
} 

- 端示例]

並再次在footnote 111 in [class.virtual]

訪問控制並不在確定首要考慮。

0

您使用虛擬析構函數,因爲您希望繼承中的所有析構函數都被調用。這正是你得到的。私人不適用,因爲你不明確調用析構函數。

如果你的析構函數不是虛擬的,你將只獲得Base::~Base()調用。通常,當你有多態性時,這不是你想要的。

0

您可以通過指向B的指針調用析構函數,因爲它已經在那裏公開。在這種情況下,它是用來確定訪問的指針的靜態類型。

[class.access.virt/1]

爲虛擬功能的訪問規則(第[class.access])是 通過其聲明確定,並且不受用於 功能,後來將覆蓋它的規則。 [實施例:

class B { 
public: 
    virtual int f(); 
}; 

class D : public B { 
private: 
    int f(); 
}; 

void f() { 
    D d; 
    B* pb = &d; 
    D* pd = &d; 

    pb->f();      // OK: B​::​f() is public, D​::​f() is invoked 
    pd->f();      // error: D​::​f() is private 
} 

- 端示例]

這保持與Liskov Substitution Principle

0

在線路虛擬函數您通過基類指針刪除派生類。在虛擬析構函數的幫助下,您可以在派生類中開始刪除操作。由於該類可以訪問其私有成員,因此它會調用私有析構函數。之後,基類正在調用公共析構函數。

請注意,您致電刪除而不是調用de析構函數Derived ::〜Derived()direct!