2015-06-04 11 views
7

Hier einige erfundene Beispiel Code:C++: Erbt es von einer Klasse es in den Namespace?

template<typename T> void Do(T arg) { (void)arg->b; } 

namespace A { 
    struct Foo { int a; }; 
} 

namespace B { 
    struct Foo { int b; }; 
    struct Bar : A::Foo { 
     void Blah() { Do((Foo *)0); } 
    }; 
} 

die, wenn sie mit gcc 4.8.2 (Klirren gibt einen ähnlichen Fehler) zusammengestellt:

namespacebug.cpp: In instantiation of ‘void Do(T) [with T = A::Foo*]’: 
namespacebug.cpp:10:34: required from here 
namespacebug.cpp:1:39: error: ‘struct A::Foo’ has no member named ‘b’ 
template<typename T> void Do(T arg) { (void)arg->b; } 
            ^

Hinweis in den Fehler es bei der zu T = A::Foo selbst bezieht sich allerdings Call-Site Ich erstelle eine Foo in Namespace B. Wenn ich die Basisklasse decl (: A::Foo) entferne, dann kompiliert alles gut.

Dies scheint darauf hinzudeuten, dass die Erben von A::Foo bringt es irgendwie in meinen Namespace und passt es an meine Verwendung von Foo? Was bewirkt C++ "feature"?

(Natürlich kann dieses Problem leicht durch meine Namensräume Verwendung von Foo festgelegt werden, aber das ist nicht die Frage.)

+0

'(void) arg-> b;' - was bedeutet das? –

+2

@EdHeal, ich denke, das ist nur da, um den Fehler zu erzwingen – StoryTeller

+0

@StoryTeller - Also, was ist der Sinn dumm zu machen? –

Antwort

5

Wegen der injizierten-Klasse-Namen ist in der Regel der Name einer Klasse sichtbar, als ob es ein Mitglied war.

9/2

A class-name wird in den Rahmen eingesetzt, in dem es sofort erklärt wird, nachdem der class-name gesehen wird.Die Klassenname wird auch in den Bereich der Klasse selbst eingefügt; Dies ist bekannt als injected-class-name. Für Zwecke der Zugriffsprüfung wird der Name der injected-Klasse so behandelt, als wäre er ein öffentlicher Membername.

So ist es, als ob Klasse A::Foo enthält ein Mitglied FooA::Foo die Art, die Namen. Da die Namenssuche in Bar::Blah() Basiselemente von Bar vor Namespacemitgliedern berücksichtigt, findet der Name lookup für Foo den Klassennamen injected-class mit dem Namen A::Foo.

+0

Danke! das ist es. – Aardappel

3

aus einer Klasse Hat erbt es in den Namensraum bringen?

Sortieren von. Wenn das Nachschlagen eines Namens in der Klasse fehlschlägt, wird die Suche in der Basisklasse fortgesetzt.

10,2 Mitglied Namenssuche

...

5 Andernfalls (dh nicht C keine Erklärung von f enthalten oder den resultierenden Deklarationssatz leer ist), S(f,C) zunächst leer. Wenn C Basisklassen hat, berechnen Sie die Suche für f in jeder direkten Basisklasse subobject gesetzt Bi und verschmelzen jede solche Lookup S(f,Bi) wiederum in S(f,C) gesetzt.

Mitglied Namenssuche enthält auch Nachschlag von verschachtelten Typen. Später im selben Abschnitt, finden wir:

9 [Hinweis: Ein statisches Element, eine verschachtelte Art oder einen Enumerator in einer Basisklasse T definiert eindeutig gefunden werden, auch wenn ein Objekt mehr als eine Basis hat Klassenunterobjekt vom Typ T. Zwei Unterobjekte der Basisklasse teilen sich die nicht statischen Teilunterobjekte ihrer gemeinsamen virtuellen Basisklassen. -Ende note]

+1

Das ist für Mitglieder. Dies ist ein Typ, kein Member und stimmt mit dem Typ der Basisklasse überein. – Aardappel

+0

@Aardappel Korrigieren. Der Name der eingefügten Klasse ist jedoch ein Mitglied der Basisklasse und wird wie andere Member vererbt. So können Sie Dinge wie 'struct A {}; Struktur B: A {}; int main() {B :: A(); } '. – hvd

+0

@Aardappel, die Namenssuche enthält auch verschachtelte Typen. Siehe mein Update. –

Verwandte Themen