2015-11-04 13 views
9

Kompilując następujący przykład w MSVC, mamZachowanie kwalifikowanej nazwy używając prywatnego dziedziczenia

„Interfejs” nie jest dostępna z powodu zastosowania „podstawowego” „prywatny” do dziedziczą z „Interfejs”

w wierszu oznaczonym Error. Gdy wywołanie foo jest kwalifikowane za pomocą aliasu typu tego samego typu, to działa. Testowałem z msvc i ideone.

Dlaczego te dwa połączenia nie są równe?

struct Interface {}; 

template<class T> 
struct Base : private T 
{ 
    void foo() {} 
}; 

using BaseX = Base<Interface>; 

class Derived : Base<Interface> 
{ 
    Derived() { 
     Base<Interface>::foo(); // Error 
     BaseX::foo();    // Works 
    } 
}; 

Ideone

+0

Wygląda jak błąd msvc –

+0

@ DieterLücking, próbowałem go używając g ++ 4.9.3 i 'BaseX :: foo();' działa. –

Odpowiedz

5

Nastrzyknięte-Class-names.

Nazwa Interface jest wtryskiwany do zakresu klasy Interface jakby był członkiem publicznej, a to z kolei odziedziczył Base<Interface> (jako członek prywatnego, ponieważ używasz prywatnego dziedziczenia).

Kiedy piszesz Base<Interface>::foo() w Derived, nazwa niewykwalifikowany odnośnika do Interface patrzy najpierw na Derived i jej klasy bazowej, znajdzie Interface w klasie bazowej, a następnie uzyskać dostęp do kopnięć kontrolnych w dlatego, że nazwa jest private.

Najprostszym rozwiązaniem jest po prostu napisz Base::foo(), lub nawet tylko foo() jeśli nie jest wirtualny i nie planuje napisać foo() w Derived.

Jeśli musisz podać argument szablonu z jakiegoś powodu, wpisz Base<::Interface>.

+1

Dlaczego jednak szukamy 'Interface'? – Barry

+0

@ Barry Um, napisałeś 'Base :: foo();' ... nie wiesz, dlaczego myślisz, że nie zostanie wyświetlony. –

+0

@Barry Cóż, zanim przejdziemy do 'foo', musimy wiedzieć, w jakim zakresie szukać (lub, czym jest' Base ') ... więc szukasz' Base' i 'Interface'. –