2017-08-09 74 views
1

儘管我已經看到final和虛擬繼承方法實現了這一點,但我不明白爲什麼定義沒有構造函數,除了默認的私有構造函數,並不妨礙類被繼承。 (另外,基類的拷貝構造函數和拷貝賦值方法應該作爲預防措施聲明爲私有)。通過定義默認私有構造函數使類不可繼承

基本上我的意思是如果一個基類的構造函數是私有的並且沒有其他構造函數,那麼當派生類想要擴展這個基類:

  1. 派生類不能調用基類的默認的構造,因爲它定義的私人

  2. 派生類不能調用基類的任何非默認構造自沒有這樣的構造函數

所以這是一個編譯時錯誤,我找不到另一種方法來克服這個問題。

我確定我錯了某個地方;否則,我可以在互聯網上找到一個頁面,將其作爲讓一個類不可繼承的方法,但請向我解釋爲什麼我錯了。

+0

你也可以使用你的方法。如果你深入挖掘,你可能會發現這兩種方法有何不同,以及何時應該使用一種方法。 –

+0

我不確定你在這裏問什麼。你是否想知道*這是否可行,或者*爲什麼它可以工作,或者如何避開它? – meagar

+0

@R Sahu請你解釋一下這個區別或者提供我可以閱讀的鏈接相關的關鍵詞嗎? – mualloc

回答

2

final和私有的構造是不一樣的東西。

考慮一下:

struct A final {}; 
struct B: A {}; 

int main() {} 

它不會編譯,這是一個事實。
現在考慮這個:

class A { A() {} }; 
struct B: A {}; 

int main() {} 

它編譯。好吧,碰巧B()構造函數被刪除,但你沒有使用它。如果你改變輕微的定義,它不會編譯:

struct B: A { B(): A() {} }; 

不管怎樣,前面的例子只是工作(爲一些平均工作),所以有什麼區別?
final禁止繼承。私人構造函數不允許你構造類型的對象類型,但你仍然可以定義類型的類型。因此,你可以做這樣的事情(這並沒有太大的意義,但給你一個想法):

#include<type_traits> 

class A { A() {}}; 
struct B: A {}; 

template<typename T> 
void f() { 
    static_assert(std::is_base_of<A, B>::value, "!"); 
    // ... 
} 

int main() { 
    f<B>(); 
} 

它怎麼說,如果你不能從A繼承編譯?由於您的假設錯誤,您可以繼承A。您不能構造B類型的對象,但只要您不嘗試創建實例,仍然可以使用B作爲類型。另一方面,如果你把final放在那裏,你會得到一個編譯時錯誤,就是這樣,你不能以任何方式使用類型B

+1

class A的構造函數是公共的,所以它不是我所說的。 – mualloc

+1

@mualloc類的默認可見性是'private',因此'class C {C(){}};'相當於'class C {private:C(){}};'。構造函數實際上並不公開。如果你嘗試在第二個例子中構造一個'B',它將不會被編譯。 – skypjack

+1

好吧,您對默認的可見性問題是正確的,並感謝您的解釋。這正是我所期待的。 – mualloc

0

爲什麼標準禁止?理論上,沒有什麼能夠阻止你將Derived類聲明爲Base類的一個朋友。這將確保擴展您的基類的唯一可能方式是通過非常知名的類。我想不出任何實際情況,我認爲這是不好的,但它是可以做到這樣的恐怖......

struct BaseClass 
{ 
friend struct DerivedClass; 

private: 
    BaseClass() {} 
}; 

struct DerivedClass : BaseClass 
{ 
public: 
    DerivedClass() {} 
}; 
相關問題