2016-08-23 130 views
46

爲什麼類D編譯,但C類不?從C++中的私有模板類繼承構造函數

class A 
{ 
    public: 
     A(int) {} 
}; 

template <class T> 
class B : private T // Note: private base class 
{ 
    public: 
     using T::T; 
}; 

class C : public B<A> 
{ 
    public: 
     C() : B<A>(123) {} // Error: 'class A A::A' is inaccessible 
};       //   within this context 

using BA = B<A>; 

class D : public BA 
{ 
    public: 
     D() : BA(123) {} // OK 
}; 

我用GCC,Clang和Visual C++測試過,它們都是一樣的。 將class B : private T更改爲public T可解決此問題。但爲什麼? (請注意,using T::Tpublic

+0

我已經添加了「模板」標籤來吸引人物。請直接批評我的「標記垃圾郵件」。 – Bathsheba

+0

這將證明模板標籤,實際上類模板中的名稱查找略有不同。 – MSalters

回答

42

A包含在其範圍內注入的類名A(即A::AA類除非它指的是構造函數)。

類繼承B此,所以B範圍內的名稱A指注射類名AA範圍。但是,由於AB的私有基類,所以在A範圍內的所有名稱在B內都是私有的。

C再次繼承此,但它不能訪問此A,因爲它在B內是私人的。因此錯誤。請注意,該錯誤實際上是在構造B<A>中使用名稱A

BA沒有這個問題,因爲定義B<A>是不是在任何類別的範圍,故得名A指的是全局名稱A,而不是任何注入的類名。當然,名稱BA是公開的。

您可以輕鬆地在C限定名稱A解決這個問題:

class C : public B<A> 
{ 
public: 
    C() : B<::A>(123) {} 
}; 

注意,構造繼承了有沒有效果。問題是訪問名稱A(注入A並繼承於BC),而不能訪問構造函數。

+1

所以,在其他(窮人)術語中,錯誤是它試圖訪問(讓我說)_wrong_命名空間(即類「B」)中的名稱'A',我錯了嗎?起首。十分有趣。 – skypjack

+0

訪問該類的私人會員@skypjack –

+0

@skypjack是的,就是這樣。另一種說法是,私有的,因此無法訪問的類名稱「A」隱藏(可訪問的)全局名稱「A」。 – Angew