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 .cppDatei 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 ( .cppDatei) 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.cppund Main.cppmüssen mit einbezogen werden Foo.h. Foo.cppbenötigt es, weil es den Code definiert, der die Klassenschnittstelle unterstützt. Daher muss es wissen, was diese Schnittstelle ist. Main.cppbenö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.odaraus Foo.cppden gesamten Foo-Klassencode in kompilierter Form. Es generiert Main.oauch die Hauptmethode und nicht aufgelöste Verweise auf die Klasse Foo.
Jetzt kommt der Linker, der die beiden Objektdateien kombiniert Foo.ound Main.oin eine ausführbare Datei. Es sieht die ungelösten Foo-Referenzen in Main.o, sieht aber, dass diese Foo.odie notwendigen Symbole enthalten, so dass es sozusagen "die Punkte verbindet". Ein Funktionsaufruf Main.oist nun mit der tatsächlichen Position des kompilierten Codes verbunden, sodass das Programm zur Laufzeit zur richtigen Position springen kann.
Wenn Sie die Foo.cppDatei Main.cppeingefü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.cppaber warum ist es dann in einer separaten .cppDatei?)
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 .cDatei ohne Compiler-Optionen und es wird C angenommen, während eine .ccoder eine .cppErweiterung es veranlassen würde, C ++ anzunehmen. Ich kann einem Compiler jedoch leicht anweisen, eine .hoder sogar eine .docxDatei 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.hund sehe Foo.cpp, gehe ich sofort davon aus, dass die erste die Deklaration der Klasse und die zweite die Definition enthält.