2016-08-23 1 views
46

Warum kompiliert Klasse D, Klasse C nicht?Vererbung eines Konstruktors aus einer privaten Schablonenklasse in 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 
}; 

ich mit GCC getestet, Clang und Visual C++, und sie sind alle gleich. Das Ändern class B : private T zu public T löst das Problem. Aber warum? (Beachten Sie, dass die using T::T ist public.)

+0

Ich habe das "templates" -Tag hinzugefügt, um die Hotshots zu kontaktieren. Bitte richten Sie Kritik an "Tag Spamming" an mich. – Bathsheba

+0

Das würde das Template-Tag rechtfertigen, und in der Tat unterscheidet sich die Namenssuche in Klassenvorlagen subtil. – MSalters

Antwort

42

Klasse A enthält das injizierte-class-name A in ihrem Umfang (das heißt, A::A bezieht sich auf Klasse A wenn es an den Konstruktor beziehen passiert).

B Klasse erbt diese, so dass der Name A im Rahmen der B bezieht sich auf den injizierte-class-namen A in Umfang A. Da A jedoch eine private Basisklasse von B ist, sind alle Namen im Bereich A innerhalb von B privat.

Die Klasse C erbt dies erneut, aber sie kann nicht auf diese A zugreifen, da sie innerhalb von B privat ist. Daher der Fehler. Beachten Sie, dass der Fehler tatsächlich bei der Verwendung des Namens A im Konstrukt B<A> auftritt.

Klasse BA dieses Problem nicht haben, da die Definition B<A> nicht in dem Geltungsbereich einer Klasse ist, so der Name A auf den globalen Namen bezieht sich A und nicht auf einen injizierte-Klasse-Namen. Und natürlich ist der Name BA öffentlich.

Sie können dies leicht lösen, indem Sie den Namen der Qualifikation A in C:

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

Beachten Sie, dass Konstruktor Vererbung es hat keine Wirkung. Das Problem ist mit Zugriff auf die Klasse Name A (in A injiziert und vererbt in B und C), nicht mit Zugriff auf den Konstruktor.

+1

Also, in anderen (schlechten) Begriffen ist der Fehler, dass es versucht, auf den Namen 'A' im (sagen wir mal) _wrong_ Namespace (dh die Klasse' B') zuzugreifen, bin ich falsch? Chapeau. Wirklich interessant. – skypjack

+0

Zugriff auf ein privates Mitglied dieser Klasse @skypjack –

+0

@skypjack Ja, das ist es. Eine andere Möglichkeit ist, dass der private und daher nicht zugängliche Klassenname "A" den (zugänglichen) globalen Namen "A" verbirgt. – Angew

Verwandte Themen