2012-08-06 5 views
6
void foo() 
{ 
    bar();   // error: ‘bar’ has not been declared 
} 

void bar() 
{ 
} 

namespace N 
{ 
    void foo() 
    { 
     N::bar(); // error: ‘bar’ is not a member of ‘N’ 
    } 

    void bar() 
    { 
    } 
} 

class C 
{ 
    static void foo() 
    { 
     C::bar(); // works just fine 
    } 

    static void bar() 
    { 
    } 
}; 

Was ist der Grund für diese Inkonsistenz bei der Behandlung von Aufrufen von Funktionen oberhalb ihrer Deklaration? Wie kann ich es innerhalb einer Klasse tun, aber nicht in einem Namensraum oder auf globaler Ebene?Aufruf von Funktionen über ihre Deklaration

+0

Vielleicht gelangt Compiler mehrfach durch Klassenmethode Implementierungen innerhalb Klassendeklaration, während „C“ Compiler nur einmal durchläuft. Könnte ein Vermächtnis sein, da foo() ist im Wesentlichen C-Funktion –

+0

Und was ist das Ergebnis nach dem Entfernen von statischen aus statischen void foo ?? – perilbrain

+0

@ Anonym, das ändert nichts – SingerOfTheFall

Antwort

3

Sie können Elementfunktionen entweder in der Klasse oder nach der Klassendeklaration oder in einigen davon definieren.

gewisse Konsistenz mit Funktionen definiert Inline hier, die Regeln für eine Klasse zu bekommen, ist, dass es immer noch kompiliert werden muss, als ob die Funktionen nach die Klasse definiert wurden.

Ihr Code

class C { 
    static void foo() 
    { 
     C::bar(); // works just fine 
    } 

    static void bar() 
    {  } 
}; 

kompiliert die gleiche wie

class C { 
    static void foo(); 
    static void bar(); 
}; 

void C::foo() 
{ C::bar(); } 

void C::bar() 
{  } 

und jetzt gibt es keine Magie in der Sicht, da die Funktionen alle alles in der Klasse deklariert sehen können.

0

Nun, vielleicht, weil Sie Ihre Klassendeklaration an einem Ort haben, und der Compiler kann leicht die Informationen seiner Mitglieder erhalten.

Ein Namespace dagegen kann seine Dateien in vielen verschiedenen Dateien haben, und Sie können nicht erwarten, dass der Compiler durch sie hindurchschaut, weil er nicht weiß, wo er zuerst suchen soll.

Um dies zu vermeiden, verwenden Sie einfach function prototypes.

0

Ich bin nicht sicher, aber mein Gedanke ist, dass ein class etwas ein Objekt (schlecht verwendet wird), wo alle seine internen Komponenten zusammenarbeiten (allgemein gesprochen), dessen Mitglied auf jeden Fall seine Methoden benötigen.

Aber ein Namespace ist anders, Funktionen sind nicht verwandt. Dies bedeutet, dass eine Funktion nicht mit allen anderen Funktionen im Namespace arbeiten soll.

Das Teilen von Deklarationen und Definitionen ist also das Beste, was Sie tun können.

Wenn foo() Bedürfnisse bar() seine höchstwahrscheinlich in der gleichen Erklärung Datei zu gehen, und würden

1
  1. Namespaces, die Art und Weise arbeiten, wieder geöffnet werden kann und neue Dinge können in jedem Ort hinzugefügt werden. Klassen können nicht wieder geöffnet werden - alle Inhalte müssen in Einzelplatz eingegeben werden.

  2. Funktionsprototypen sind in Namespaces zulässig, aber nicht in Klassen.

Sie können

namespace n 
{ 
    void foo(); 

    void bar() 
    { 
     foo(); 
    } 

    void foo() 
    { 
    } 
} 

schreiben aber nicht

class C 
{ 
    void foo(); 

    void bar() 
    { 
     foo(); 
    } 

    void foo() 
    { 
    } 
} 

So müssen Klassen solche Funktion viel mehr und es ist viel einfacher, es als für Namensraum für sie zu implementieren.

0

Siehe unten stehendes Zitat aus der Standard-

3.3.7 Klasse Anwendungsbereich [basic.scope.class]

1) Die folgenden Regeln den Umfang der Namen in Klassen deklarierten beschreiben. 1) Der potentielle Geltungsbereich eines in einer Klasse deklarierten Namens besteht nicht nur aus dem deklarativen Bereich , der dem Deklarationspunkt des Namens folgt, sondern auch aller Funktionskörper, Standardargumente und Klammer-oder-Gleich-Initialisierer von nicht-statischem Datenelemente in dieser Klasse (einschließlich solcher Dinge in verschachtelten Klassen).

2) Ein in einer Klasse S verwendeter Name N muss in seinem Kontext auf dieselbe Deklaration verweisen und bei einer erneuten Auswertung in den vervollständigten Umfang von S. Für einen Verstoß gegen diese Regel ist keine Diagnose erforderlich.

typedef int c; 
enum { i = 1 }; 

class X { 
    char v[i]; // error: i refers to ::i 
       // but when reevaluated is X::i 
    int f() { return sizeof(c); } // OK: X::c 
    char c; 
    enum { i = 2 }; 
};