Verschachtelte Funktionen sind nicht erlaubt, aber warum verschachtelte Funktionsprototypen sind erlaubt? [C ++]

StackOverflow https://stackoverflow.com/questions/928992

Frage

Ich war die verknüpfte Frage zu lesen, die mir diese Frage zu stellen führt.

Betrachten Sie den folgenden Code

int main()
{
    string SomeString();
}

Alle sagen, Compiler dies als Funktionsprototyp nimmt und nicht als string Objekt. Betrachten wir nun den folgenden Code ein.

int main()
{
    string Some()
    {
        return "";
    }
}

Compiler sagte, dies sei ungültig, da ich verschachtelte Funktion Definition erraten ist nicht erlaubt. Wenn es nicht erlaubt ist, warum verschachtelte Funktionsprototypen sind erlaubt? Es ist kein Vorteil, anstatt zu machen Verwirrung zu geben (oder bin ich einige gültige Punkte hier fehlt?).

Ich fand heraus, folgendes gilt.

int main()
{ 
  string SomeFun();
  SomeFun();
  return 0;
}

string SomeFun()
{
  std::cout << "WOW this is unexpected" << std::endl;
}

Dies ist auch verwirrend. Ich habe erwartet, die Funktion SomeFun () einen Umfang hat nur in main . Aber ich habe mich getäuscht. Warum Compiler ermöglicht Code wie oben zu kompilieren? Gibt es eine Echtzeit-Situationen, in denen Code wie die oben genannten Sinn macht?

Alle Gedanken?

War es hilfreich?

Lösung

Ihr Prototyp ist nur ' Forward-Deklaration '. Bitte überprüfen Sie die Wikipedia-Artikel aus.

Im Grunde ist es teilt den Compiler „nicht beunruhigt, wenn das Etikett‚SomeFun‘auf diese Weise verwendet wird“. Aber Ihr Linker ist, was für die Suche nach dem richtigen Funktion Körper verantwortlich ist.

Sie können einen falschen Prototyp tatsächlich erklären, z.B. ‚Char SomeFun ()‘ und alles über Ihr Haupt verwenden. Sie werden nur eine Fehlermeldung erhalten, wenn Sie Ihren Linker den Körper Ihrer falschen Funktion zu finden versucht. Aber Ihr Compiler wird mit ihm kühl sein.

Es gibt viele Vorteile. Sie haben die Funktion Körper zu erinnern ist, nicht immer in der gleichen Quellcodedatei. Es kann in einer verknüpften library.Also sein kann, dass verknüpfte Bibliothek haben werden, um eine spezifische ‚Link signature'.Use bedingte definiert Sie auch den richtigen Link Unterschrift bei der Erstellung mit Ihrem scoped prototypes.Although die meisten Menschen Funktionszeiger würde können sich verwenden für dass statt.

Hope, das hilft.

Andere Tipps

So wie eine Randnotiz, C ++ 03 hat einen Umweg lokale Funktionen zu definieren. Es erfordert die lokalen Klasse-Funktion missbrauchen:

int main()
{
    struct Local
    {
        static string Some()
        {
            return "";
        }
    };
    std::cout << Local::Some() << std::endl;
}

Dies ist eine Konvention von C - wie viele -., Die C ++ angenommen hat

Die Fähigkeit, eine Funktion innerhalb einer anderen Funktion in C zu erklären, ist eine Entscheidung, die die meisten Programmierer wahrscheinlich bedauerlich und unnötig betrachten. Vor allem bei modernem OOP Design, bei den Funktionsdefinition sind vergleichsweise kleiner, als sie in C sind.

Wenn Sie möchten, dass Funktionen, die nur im Rahmen einer anderen Funktion existieren, sind zwei Optionen boost :: Lambda und C ++ 1x Lambda .

Wie, warum Ihre Erklärung

void f() {
    void g(); g();
}

ist besser als diese

void g();
void f() {
    g();
}

Es ist im Allgemeinen gut, wenn man Erklärungen so lokal wie möglich zu halten, so dass möglichst wenige Namenskonflikte wie möglich Ergebnis. Ich sage, es ist fraglich, ob lokal eine Funktion erklärt (auf diese Weise) ist wirklich Glück, wie ich denke, es ist immer noch besser zu gewöhnliches ist seine Header und dann den „üblichen“ Weg gehen, die auch weniger verwirrend ist, Menschen nicht darüber zu wissen. Manchmal ist es auch nützlich, um eine schattierten Funktion zu arbeiten

void f() {
    int g; 
    // oops, ::g is shadowed. But we can work around that
    {
        void g(); g();
    }
}

Natürlich in C ++ wir könnten Funktion g nennen its_namespace::g() mit - aber in den alten Tagen von C, die nicht möglich gewesen wäre, und das, was erlaubt es dem Programmierer noch die Funktion zugreifen. Beachten Sie auch, dass, während syntaktisch es nicht das gleiche ist, semantisch die folgend ist auch eine Funktion in einem lokalen Bereich erklären, dass tatsächlich einen anderen Bereich als Ziel hat.

int main() {
    using std::exit;
    exit();
}

Als Randbemerkung, gibt es mehr Situationen wie die, wo das Ziel Rahmen einer Erklärung nicht den Umfang, wenn diese Erklärung erscheint. Im Allgemeinen ist das Objekt, das Sie erklären Mitglied der wird Umfang, in dem die Erklärung erscheint. Aber das ist nicht immer der Fall. Betrachten wir zum Beispiel Freund Erklärungen, wo das geschieht

struct X { friend void f() { std::cout << "WoW"; } };
int main() { void f(); f(); } // works!

Auch wenn die Funktionsdeklaration (und Definition!) Von f im Rahmen von X passiert ist, das Unternehmen (die Funktion selbst) wurde ein Mitglied des einschließenden Namespace.

Funktionsprototypen sind Hinweise für den Compiler. Sie zeigen, dass die Funktionen anderswo umgesetzt werden, wenn sie nicht bereits entdeckt . Sonst nichts.

Wenn Sie deklarieren einen Prototyp, wie Sie Sie tun, im Grunde sagen dem Compiler für den Linker zu warten, um es zu lösen. Abhängig davon, wo Sie den Prototyp der Scoping-Regeln gelten schreiben. Es gibt nichts technisch falsch, den Prototyp in Ihrer Funktion main () zu schreiben (obwohl IMHO ein bisschen unordentliche), es bedeutet nur, dass die Funktion nur lokal innerhalb des Hauptes bekannt ist (). Wenn Sie den Prototyp an der Spitze der Quelldatei (oder häufiger in einer Header-Datei) erklärt habe, würde der Prototyp / Funktion in der gesamten Quelle bekannt sein.

string foo()
{
  string ret = someString();  // Error
  return ret; 
}

int main(int argc,char**argv)
{
   string someString();
   string s = somestring(); // OK
   ...
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top