Sie können zwar.cpp
Dateien wie erwähnt einschließen , dies ist jedoch keine gute Idee.
Wie Sie bereits erwähnt haben, gehören Deklarationen in Header-Dateien. Diese verursachen keine Probleme, wenn sie in mehreren Kompilierungseinheiten enthalten sind, da sie keine Implementierungen enthalten. Das mehrfache Einfügen der Definition einer Funktion oder eines Klassenmitglieds verursacht normalerweise ein Problem (aber nicht immer), da der Linker verwirrt wird und einen Fehler auslöst.
Was passieren sollte, ist, dass jede .cpp
Datei Definitionen für eine Teilmenge des Programms enthält, wie z. B. eine Klasse, eine logisch organisierte Gruppe von Funktionen, globale statische Variablen (wenn überhaupt, sparsam verwenden) usw.
Jede Kompilierungseinheit ( .cpp
Datei) enthält dann alle Deklarationen, die zum Kompilieren der darin enthaltenen Definitionen erforderlich sind. Es verfolgt die Funktionen und Klassen, auf die es verweist, die es jedoch nicht enthält, sodass der Linker sie später auflösen kann, wenn er den Objektcode in eine ausführbare Datei oder Bibliothek kombiniert.
Beispiel
Foo.h
-> enthält Deklaration (Interface) für Klasse Foo.
Foo.cpp
-> enthält die Definition (Implementierung) für die Klasse Foo.
Main.cpp
-> enthält Hauptmethode, Programmeinstiegspunkt. Dieser Code instanziiert ein Foo und verwendet es.
Beides Foo.cpp
und Main.cpp
müssen mit einbezogen werden Foo.h
. Foo.cpp
benötigt es, weil es den Code definiert, der die Klassenschnittstelle unterstützt. Daher muss es wissen, was diese Schnittstelle ist. Main.cpp
benötigt es, weil es ein Foo erstellt und sein Verhalten aufruft. Daher muss es wissen, was dieses Verhalten ist, wie groß ein Foo im Speicher ist und wie es seine Funktionen findet usw., aber es benötigt noch keine eigentliche Implementierung.
Der Compiler generiert Foo.o
daraus Foo.cpp
den gesamten Foo-Klassencode in kompilierter Form. Es generiert Main.o
auch die Hauptmethode und nicht aufgelöste Verweise auf die Klasse Foo.
Jetzt kommt der Linker, der die beiden Objektdateien kombiniert Foo.o
und Main.o
in eine ausführbare Datei. Es sieht die ungelösten Foo-Referenzen in Main.o
, sieht aber, dass diese Foo.o
die notwendigen Symbole enthalten, so dass es sozusagen "die Punkte verbindet". Ein Funktionsaufruf Main.o
ist nun mit der tatsächlichen Position des kompilierten Codes verbunden, sodass das Programm zur Laufzeit zur richtigen Position springen kann.
Wenn Sie die Foo.cpp
Datei Main.cpp
eingefügt hätten, gäbe es zwei Definitionen der Klasse Foo. Der Linker würde dies sehen und sagen: "Ich weiß nicht, welchen ich wählen soll, also ist dies ein Fehler." Der Kompilierungsschritt wäre erfolgreich, das Verknüpfen jedoch nicht. (Es sei denn, Sie kompilieren einfach nicht, Foo.cpp
aber warum ist es dann in einer separaten .cpp
Datei?)
Schließlich ist die Idee der verschiedenen Dateitypen für einen C / C ++ - Compiler irrelevant. Es kompiliert "Textdateien", die hoffentlich gültigen Code für die gewünschte Sprache enthalten. Manchmal kann es vorkommen, dass die Sprache anhand der Dateierweiterung ermittelt wird. Kompilieren Sie zum Beispiel eine .c
Datei ohne Compiler-Optionen und es wird C angenommen, während eine .cc
oder eine .cpp
Erweiterung es veranlassen würde, C ++ anzunehmen. Ich kann einem Compiler jedoch leicht anweisen, eine .h
oder sogar eine .docx
Datei als C ++ zu kompilieren , und er gibt eine object ( .o
) - Datei aus, wenn sie gültigen C ++ - Code im Nur-Text-Format enthält. Diese Erweiterungen kommen eher dem Programmierer zugute. Wenn ich Foo.h
und sehe Foo.cpp
, gehe ich sofort davon aus, dass die erste die Deklaration der Klasse und die zweite die Definition enthält.