2016-08-23 11 views
46

Dlaczego kompilacja klasy D jest kompilowana, ale klasa C nie?Dziedziczenie konstruktora z prywatnej klasy szablonów w 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 
}; 

testowałem z GCC, Clang i Visual C++, i wszystkie są takie same. Zmiana class B : private T na public T rozwiązuje problem. Ale dlaczego? (Zauważ, że using T::T jest public.)

+0

Dodałem znacznik "templates", aby sprawdzić hotshoty. Skieruj wszelkie uwagi krytyczne do "spamowania tagów". – Bathsheba

+0

To usprawiedliwiłoby tag szablonu, a nawet wyszukiwanie nazw w szablonach klas jest nieco inne. – MSalters

Odpowiedz

42

Klasa A zawiera wstrzykuje-nazwa-klasy A w jej zakres (czyli A::A odnosi się do klasy A chyba zdarza się odnieść do konstruktora).

klasy B dziedziczy to więc nazwa A zakresem B dotyczy wtryskiwanego klasy I nazwą A w zakresie A. Jednak ponieważ A jest prywatną klasą bazową B, wszystkie nazwy w zakresie A są prywatne w zakresie B.

Klasa C ponownie dziedziczy to, ale nie może uzyskać dostępu do tego A, ponieważ jest prywatny w zakresie B. Stąd błąd. Zauważ, że błąd polega na użyciu nazwy A w konstrukcji B<A>.

Klasa BA nie ma tego problemu, ponieważ definicja B<A> nie jest w zakresie dowolnej klasy, więc nazwa A odnosi się do globalnej nazwy A a nie do jakiegokolwiek wtryskiwanego-nazwa-klasy. I oczywiście nazwa BA jest jawna.

można łatwo rozwiązać ten kwalifikując nazwę A w C:

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

Zauważ, że konstruktor dziedziczenie ma tam żadnego efektu. Problem polega na dostępie do klasy klasy o nazwie A (wstrzykniętej w A i odziedziczonej po B i C), a nie do dostępu do konstruktora.

+1

W innych (złych) terminach błąd polega na tym, że próbuje uzyskać dostęp do nazwy "A" w (powiedzmy) _wrong_ przestrzeni nazw (czyli klasie "B"), czy jestem w błędzie? Chapeau. Naprawdę interesujące. – skypjack

+0

Dostęp do prywatnego członka tej klasy @skypjack –

+0

@skypjack Tak, to wszystko. Innym sposobem, aby to powiedzieć, jest to, że prywatna, a tym samym niedostępna w klasie nazwa "A", ukrywa (dostępną) globalną nazwę "A". – Angew

Powiązane problemy