2013-01-16 64 views
11

前言:C++ 11刪除重寫的方法

這是一個問題,當應用到子類關於與C++ 11引入了delete操作符的新的意義的最佳實踐覆蓋繼承父的虛擬方法。

背景:

每標準,第一使用情況中引用是明確禁止調用函數對於某些類型的,其中轉化率,否則將隱式如從最新C++11 standard draft§8.4.3的例子:

struct sometype { 
    sometype() = delete; // OK, but redundant 
    some_type(std::intmax_t) = delete; 
    some_type(double); 
}; 

上面的例子很清楚,有目的。但是,下面的示例中,新操作符被覆蓋並通過將其定義爲刪除而被阻止開始,我開始考慮後來在問題部分中指出的其他場景(以下示例來自C++11 standard draft的§8.4.3):

struct sometype { 
    void *operator new(std::size_t) = delete; 
    void *operator new[](std::size_t) = delete; 
}; 
sometype *p = new sometype; // error, deleted class operator new 
sometype *q = new sometype[3]; // error, deleted class operator new[] 

問:

通過這種思想繼承的延伸,我很好奇,就以下使用示例是一個清晰而有效的用例其他的想法,或者如果它是不明確的濫用的新增功能。請提供您的答案的理由(提供最有說服力的推理的例子將被接受)。在下面的例子中,設計試圖通過讓庫的第二版本繼承第一版本來維護兩個版本的庫(該庫需要被實例化)。這個想法是允許對第一個庫版本的錯誤修復或更改自動傳播到第二個庫版本,同時允許第二個庫版本只關注與第一個版本的差異。棄用第二庫版本的函數,delete運算符是用來呼叫禁止,以重寫的功能:

class LibraryVersion1 { 
public: 
    virtual void doSomething1() { /* does something */ } 
    // many other library methods 
    virtual void doSomethingN() { /* does something else */ } 
}; 

class LibraryVersion2 : public LibraryVersion1 { 
public: 
    // Deprecate the doSomething1 method by disallowing it from being called 
    virtual void doSomething1() override = delete; 

    // Add new method definitions 
    virtual void doSomethingElse() { /* does something else */ } 
}; 

雖然我可以看到很多好處,這樣的做法,我覺得我傾向於更傾向於思想這是對該功能的濫用。我在上面的例子中看到的主要缺陷是經典的「is-a」繼承關係被打破。我讀過很多文章,強烈建議不要使用繼承來表達「一種是一種」關係,而是使用包含函數的組合來清楚地標識類的關係。儘管下面經常被忽視的例子需要更多的努力來實現和維護(關於爲這段代碼編寫的行數,由於每個繼承函數都必須公開可用,必須由繼承類明確地調用),使用如上所述的刪除在很多方面非常相似:

class LibraryVersion1 { 
public: 
    virtual void doSomething1() { /* does something */ } 
    virtual void doSomething2() { /* does something */ } 
    // many other library methods 
    virtual void doSomethingN() { /* does something */ } 
}; 

class LibraryVersion2 : private LibraryVersion1 { 
    // doSomething1 is inherited privately so other classes cannot call it 
public: 
    // Explicitly state which functions have not been deprecated 
    using LibraryVersion1::doSomething2(); 
    // ... using (many other library methods) 
    using LibraryVersion1::doSomethingN(); 

    // Add new method definitions 
    virtual void doSomethingElse() { /* does something else */ } 
}; 

非常感謝您的回答,並深入瞭解此潛在用例的刪除。

+0

我不認爲'虛擬無效doSomething1()倍率=刪除;'是合法的。有什麼辦法'((LibraryVersion1 *)(新LibraryVersion2)) - > doSomething1()'做什麼? –

+0

按我的理解,即使投給LibraryVersion1,刪除的功能仍然試圖通過LibraryVersion2被稱爲給出的倍率,導致代碼編譯失敗。正如我的問題所指出的那樣,這是「is-a」關係被打破的地方,但它肯定會按預期強制執行棄用。 – statueuphemism

+0

fresh:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3485.pdf – qPCR4vir

回答

5

段落8.4.3/2不允許對刪除它覆蓋一個虛擬函數的函數:

「一種程序,是指到已刪除的功能隱含地或明確,除了申報它,是非法的構造。[注:此包括調用函數隱含或明確地並形成一指針或指針到構件的功能」

通過一個指向基類調用壓倒一切的虛擬函數是企圖隱含調用該函數。因此,按照8.4.3/2,允許這種設計是非法的。另請注意,沒有符合C++ 11的編譯器會讓您刪除重寫的虛擬函數。 。

更明確地說,同樣通過第10.3/16規定:

「與已刪除的定義(8.4)不得覆蓋不具有已刪除的定義的功能的功能同樣地,一個函數,它沒有刪除的定義不得凌駕於功能與已刪除的定義

+1

謝謝。我不知何故錯過了那寶石。只是發現了另一個直接禁止它的引用:「一個定義被刪除的函數(8.4)不能覆蓋沒有被刪除定義的函數 同樣,一個沒有被刪除定義的函數不應該用刪除了 的定義。「 – statueuphemism

+0

@statueuphemhem:對,好點。讓我把它整合在我的回答中 –

2

考慮的一些功能:

void f(LibraryVersion1* p) 
{ 
    p->doSomething1(); 
} 

這將編譯LibraryVersion2甚至寫入之前。

因此,現在您使用已刪除的虛擬實現LibraryVersion2。

f已被編譯。它直到運行時才知道哪個LibraryVersion1子類已被調用。

這就是爲什麼刪除的虛擬是不合法的,它沒有任何意義。

最好可以做的是:的C++標準間接

class LibraryVersion2 : public LibraryVersion1 
{ 
public: 
    virtual void doSomething1() override 
    { 
     throw DeletedFunctionException(); 
    } 
} 
+0

如果我有這樣的聲望,我也會對此讚不絕口。關於「最好你可以做」的補充,雖然在運行時拋出一個異常來表示拋棄一個方法的方式似乎很混亂,但是當涉及到棄用一個函數時(我當然不希望使用這樣做的庫)。我認爲這種情況會在那個時候要求重新設計。但是你是對的,這可能是語言可以強制執行被重寫方法的一個被刪除定義的最好方式。 – statueuphemism

+0

目前還不清楚你試圖解決的問題是什麼。您似乎想要一種管理庫版本控制的方法。因此,首先編寫庫1,然後使用庫1編寫應用程序1,然後編寫庫2,並且您希望應用程序1繼續與庫2一起工作。 –

+0

我的示例有點設法,我實際上並不試圖解決問題現在。我把這個想法作爲一種潛在的方法來簡單地維護兩個軟件,其中一個軟件直接從另一個繼承而不需要任何額外的合併(類似Python 2.7,它與Python 3.0+有一些共同之處,但仍然被維護由於顯着差異)。如果您要維護從Python2_7繼承的Python3_0類,則共享代碼中的錯誤修復將自動傳播。還有其他更好的設計來完成這個。 – statueuphemism

4

10.3p16:

與已刪除的定義(8.4)的函數不得凌駕於不具有的功能削除特德的定義。同樣,一個沒有被刪除定義的函數也不能覆蓋具有被刪除定義的函數。

另一個答案解釋了爲什麼很好,但你有官方的你不應該。

+0

哦,你已經在一個不同的答案的評論中引用了它。好吧。 – aschepler