簡體   English   中英

C ++ 11接口純虛析構函數

[英]C++11 interface pure virtual destructor

UPD 有一個標記,它是這個問題的副本。 但是在那個問題上,OP問如何使用default來定義純虛析構函數。 這個問題是關於有什么區別的

在C ++(如果可能的話,最新標准)中,使用空體實現定義純虛擬析構函數和僅使用空體(或默認值)之間的真正區別是什么?

變式1:

class I1 {
public:
    virtual ~I1() {}
};

變式2.1:

class I21 {
public:
    virtual ~I21() = 0;
};

I21::~I21() {}

變式2.2:

class I22 {
public:
    virtual ~I22() = 0;
};

I22::~I22() = default;

更新我發現Variant 1和Variants 2.1 / 2.2之間至少有1個區別:

對於Variant 1, std::is_abstract::valuefalse ,對於Variants 2.1和2.2,則為true

演示

可能有人可以發現2.1和2.2之間的區別?

正如您所指出的,I1和I2 *之間的區別在於,添加= 0會使類抽象化。 事實上,當你沒有任何其他函數是純虛擬時,使析構函數成為虛擬是一個使類抽象的技巧 我說這是一個技巧,因為如果你想要破壞析構函數的任何派生類(在這里你會),析構函數不能保持未定義,那么你仍然需要定義析構函數,無論是空的還是默認的。

現在,空的或默認的析構函數/構造函數(I21和I22)之間的區別更加模糊,沒有太多的寫入。 推薦的是使用default ,作為一種新的習慣用語,使你的意圖更清晰,顯然,給編譯器一個優化的機會。 引用msdn

由於普通特殊成員函數的性能優勢,我們建議您在需要默認行為時更喜歡在空函數體上自動生成特殊成員函數。

除了可能的性能改進之外,兩者之間沒有明顯的差異。 = default是從C ++ 11開始的方式。

我能找到的只有:

§12.4(5.9)

析構函數可以聲明為虛擬(10.3)或純虛擬(10.4); 如果在程序中創建了該類或任何派生類的任何對象,則應定義析構函數。 如果類具有帶虛擬析構函數的基類,則其析構函數(無論是用戶還是隱式聲明)都是虛擬的。

導致:

§10.4(該類現在是抽象的)

10.4(2)說:

只有在使用(12.4)qualified-id語法(5.1)調用時,才需要定義純虛函數。

但是關於§12.4中的析構函數的敘述談到了析構函數總是被稱為完全限定名稱(為了防止歧義)。

意思就是:

  • 必須定義析構函數,即使是純虛擬的,也是如此

  • 這個班級現在是抽象的。

變體1將允許您擁有該類的實例。 變體2.1,2.2不允許實例,但允許后代的實例。 例如,這可以工作(並且能夠讓許多人感到困惑),而刪除標記的行會使編譯失敗:

class I21 {
public:
    virtual ~I21() = 0;
};

I21::~I21() {} // remove this and it'll not compile

class I22 : public I21
{
public:
    virtual ~I22() {}
};

int main() {
    I22 i;
    return 0;
}

后面的原因,析構函數鏈直接調用I21 ::〜I21()而不是通過接口。 也就是說,目前尚不清楚純虛擬析構器的目標是什么。 如果您想避免實例化(即靜態類),您可以考慮刪除構造函數; 如果你想要可以實例化但不是這個類的后代,也許你需要一個在后代中實現的純虛擬成員函數。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM