2016-09-06 1 views
25

Aufgrund des Layouts einer Bibliothek von Drittanbietern, habe ich so etwas wie den folgenden Code:So rufen Sie eine statische Methode von einer privaten Basisklasse auf?

struct Base 
{ 
    static void SomeStaticMethod(){} 
}; 

struct Derived1: private Base {}; 

struct Derived2: public Derived1 { 
    void SomeInstanceMethod(){ 
     Base::SomeStaticMethod(); 
    } 
}; 

int main() { 
    Derived2 d2; 
    d2.SomeInstanceMethod(); 

    return 0; 
} 

Ich C2247 immer Compiler-Fehler mit MSVC:

Basis :: SomeStaticMethod nicht zugänglich Weil Derived1 private verwendet, um von Base zu erben.

Ich weiß, dass ich nicht Base Mitglieder aus Derived2 über Vererbung wegen des privaten Spezifizierer zugreifen können, aber ich sollte noch eine statische Methode von Base aufrufen können, - unabhängig von einer Vererbungsbeziehung zwischen Base und Derived2.
Wie kann ich die Mehrdeutigkeit auflösen und dem Compiler mitteilen, dass ich gerade eine statische Methode aufruft?

Antwort

22

tun:

struct Derived2: public Derived1 { 
    void SomeInstanceMethod(){ 
     ::Base::SomeStaticMethod(); 
//  ^^ 
//  Notice leading :: for accessing root namespace. 
    } 
}; 
+0

Dies funktioniert nicht (gleicher Fehler C2247). Ich verwende MSVC 2013, wenn das relevant ist. – Carlton

+1

Sind Sie sicher? Es sollte funktionieren? Hast du das führende '::' geschrieben? – Bathsheba

+0

Positiv. Ich habe Ihren Code kopiert/eingefügt und mein Projekt gereinigt/neu erstellt. – Carlton

5

Sie können dies tun, wenn Sie es durch die Hierarchie nennen wollen:

struct Derived1: private Base { 
protected: 
    using Base::SomeStaticMethod; 
}; 

struct Derived2: public Derived1 { 
    void SomeInstanceMethod(){ 
     Derived1::SomeStaticMethod(); 
    } 
}; 

Ansonsten tun, wie @michalsrb erwähnt, wenn Sie es möchten direkt anrufen Base.

4

Ein paar Möglichkeiten:

  1. Verwenden Sie die Vererbungsstruktur nicht die Methode aufzurufen. Verwenden Sie ::Base::SomeStaticMethod(), um es aufzurufen. Base ist im globalen Namespace verfügbar.

  2. Bringen Sie die private Funktion in den Namensraum von Derived1 von using Base::SomeStaticMethod;

8

Schreiben Ich denke michalsrb Antwort ist besser, aber der Vollständigkeit halber:

namespace 
{ 
    void SomeStaticMethodProxy() 
    { 
     return Base::SomeStaticMethod(); 
    } 
} 

struct Derived2: public Derived1 { 
    void SomeInstanceMethod(){ 
     SomeStaticMethodProxy(); 
    } 
}; 

wird auch funktionieren.

7

Andere Antworten bieten Möglichkeit, das Problem zu lösen, ich werde versuchen zu erklären, was passiert. Es ist wegen injected-class-name.

9.2 (N4594)

[...] Der Klassenname ebenfalls in den Schutzbereich der Klasse eingeführt wird selbst; Dies wird als der Name der injected-Klasse bezeichnet. Für Zwecke der Zugriffsprüfung wird der Name der eingefügten Klasse so behandelt, als wäre es ein öffentlicher Membername. [...]

]

Beachten Sie, dass, auch wenn Sie Base::SomeStaticMethod() eingeben, offensichtlich SomeStaticMethod in Base Umfang nachgeschlagen (es ist qualifizierter Name), aber Name Base selbst muss auch irgendwie nachgeschlagen werden, (in diesem Beispiel als unqualifizierte Namen (weil es nicht erscheint, nachdem Bereichsauflösungsoperator))

Was passiert, ist, dass, wenn Sie für (unqalified) Namen Base in Derived2 zunächst Derived2 Suchbereich gesucht wird, dann Derived1 s cope wird gesucht und dann wird Base scope gesucht und schließlich injected-class-name gefunden. Dann findet die Zugriffskontrolle statt (weil die Zugriffskontrolle stattfindet nach Namenssuche) und es wird finden, dass der Name, den Sie nachgeschlagen haben, Base 's Mitglied ist, auf das von Derived2 nicht zugegriffen werden kann.

+0

Sehr gute Analyse, warum dies passiert. Vielen Dank. – Carlton

+0

@Carlton Gern geschehen – PcAF

+0

Brilliant! Ich ahnte, dass so etwas passieren muss, aber das macht es sehr klar * genau * was passiert (und erklärt warum das Setzen von '::' auf der Vorderseite das Problem behebt). –

Verwandte Themen