Warum Forward-Declaration in C ++ erforderlich ist
Der Compiler möchte sicherstellen, dass Sie keine Rechtschreibfehler gemacht oder die falsche Anzahl von Argumenten an die Funktion übergeben haben. Es besteht also darauf, dass zuerst eine Deklaration von 'add' (oder anderen Typen, Klassen oder Funktionen) angezeigt wird, bevor es verwendet wird.
Dies ermöglicht es dem Compiler wirklich nur, den Code besser zu validieren, und ermöglicht es ihm, lose Enden aufzuräumen, um eine ordentlich aussehende Objektdatei zu erstellen. Wenn Sie keine deklarierten Dinge weiterleiten müssten, würde der Compiler eine Objektdatei erstellen, die Informationen über alle möglichen Vermutungen darüber enthalten müsste, wie die Funktion 'hinzufügen' aussehen könnte. Und der Linker müsste eine sehr clevere Logik enthalten, um herauszufinden, welches 'Add' Sie tatsächlich aufrufen möchten, wenn die 'Add'-Funktion in einer anderen Objektdatei gespeichert ist, die der Linker mit der verbindet, die Add zum Produzieren verwendet eine DLL oder Exe. Es ist möglich, dass der Linker das falsche Add erhält. Angenommen, Sie wollten int add (int a, float b) verwenden, haben aber versehentlich vergessen, es zu schreiben, aber der Linker hat ein bereits vorhandenes int add (int a, int b) und dachte, das sei das Richtige und benutzte das stattdessen. Ihr Code würde kompiliert, würde aber nicht das tun, was Sie erwartet hatten.
Um die Dinge explizit zu halten und das Raten usw. zu vermeiden, besteht der Compiler darauf, dass Sie alles deklarieren, bevor es verwendet wird.
Unterschied zwischen Deklaration und Definition
Nebenbei ist es wichtig, den Unterschied zwischen einer Deklaration und einer Definition zu kennen. Eine Deklaration gibt nur genug Code, um zu zeigen, wie etwas aussieht. Für eine Funktion ist dies also der Rückgabetyp, die Aufrufkonvention, der Methodenname, die Argumente und deren Typen. Der Code für die Methode ist jedoch nicht erforderlich. Für eine Definition benötigen Sie die Deklaration und dann auch den Code für die Funktion.
Wie Forward-Deklarationen die Erstellungszeiten erheblich verkürzen können
Sie können die Deklaration einer Funktion in Ihre aktuelle CPP- oder H-Datei aufnehmen, indem Sie # den Header einschließen, der bereits eine Deklaration der Funktion enthält. Dies kann jedoch Ihre Kompilierung verlangsamen, insbesondere wenn Sie einen Header in ein .h anstelle von .cpp Ihres Programms einschließen, da alles, was das von Ihnen geschriebene .h einschließt, am Ende alle Header enthält Sie haben auch #includes für geschrieben. Plötzlich enthält der Compiler # Seiten und Codeseiten, die er kompilieren muss, selbst wenn Sie nur eine oder zwei Funktionen verwenden möchten. Um dies zu vermeiden, können Sie eine Vorwärtsdeklaration verwenden und die Deklaration der Funktion selbst oben in die Datei eingeben. Wenn Sie nur wenige Funktionen verwenden, können Ihre Kompilierungen dadurch schneller ausgeführt werden, als wenn Sie immer den Header einschließen. Für wirklich große Projekte,
Unterbrechen Sie zyklische Referenzen, bei denen sich zwei Definitionen gegenseitig verwenden
Darüber hinaus können Vorwärtsdeklarationen Ihnen helfen, Zyklen zu unterbrechen. Hier versuchen zwei Funktionen, sich gegenseitig zu nutzen. Wenn dies passiert (und es ist eine absolut gültige Sache), können Sie # eine Header-Datei einschließen, aber diese Header-Datei versucht, # die Header-Datei einzuschließen, die Sie gerade schreiben .... was dann # den anderen Header einschließt , welches # das enthält, das Sie schreiben. Sie befinden sich in einer Henne-Ei-Situation, in der jede Header-Datei versucht, die andere wieder einzuschließen. Um dies zu lösen, können Sie die benötigten Teile in einer der Dateien vorwärts deklarieren und das #include aus dieser Datei herauslassen.
Z.B:
Datei Car.h.
#include "Wheel.h" // Include Wheel's definition so it can be used in Car.
#include <vector>
class Car
{
std::vector<Wheel> wheels;
};
Datei Wheel.h
Hmm ... die Deklaration von Car ist hier erforderlich, da Wheel einen Zeiger auf ein Car hat, aber Car.h kann hier nicht aufgenommen werden, da dies zu einem Compilerfehler führen würde. Wenn Car.h enthalten wäre, würde dies versuchen, Wheel.h einzuschließen, das Car.h enthält, das Wheel.h enthält, und dies würde für immer weitergehen, sodass der Compiler stattdessen einen Fehler auslöst. Die Lösung besteht darin, stattdessen das Auto weiterzuleiten:
class Car; // forward declaration
class Wheel
{
Car* car;
};
Wenn die Klasse Wheel Methoden hatte, die Methoden von car aufrufen müssen, könnten diese Methoden in Wheel.cpp definiert werden, und Wheel.cpp kann jetzt Car.h einschließen, ohne einen Zyklus zu verursachen.