Warum .cpp-Dateien verwenden, wenn ich meinen gesamten C++ - Code in der .h-Datei haben kann? Ich meine, CPP-Dateien sind ziemlich seltsam zu verwenden, wenn der gesamte Code in .h-Datei geschrieben werden kann? Kann jemand aufklären?Warum .cpp-Dateien verwenden, wenn ich meinen gesamten C++ - Code in der .h-Datei haben kann?
Antwort
Einige Gründe:
(1) Incremental Bauzeiten
Wenn Projekte größer werden, die Verwaltung der Aufbauzeit vor allem für C++ Projekte problematisch ist. Gebäude 1 oder 5 Minuten nach einer kleinen Änderung macht einen großen Unterschied. Dies wird durch die meisten Änderungen in großen Projekten betont, die klein sind und erfordern eine Menge Tests. Fügen Sie dazu einen Versuch von TDD und Refactoring hinzu, und Sie sind eine tote Schnecke mit sizilianischen Schuhen.
Die Aufteilung in Header und Body und das Verschieben in libs verbessert die inkrementellen Build-Zeiten enorm.
(2) Statiken
Für viele Dinge, die Sie eine einzelne Instanz eines Typs benötigen, dh
// .cpp
static Foo foo;
Es gibt keine Möglichkeit (die ich bin mir dessen bewusst) ermöglicht dies in einem Header- nur Projekt. Compiler-spezifische Lösungen sind begrenzt, z. __declspec(selectany)
in MSVC ist auf POD-Typen beschränkt.
(3) Implementierung versteckt
CPP/.h Trennung ist der einzige Weg, um eindeutig eine öffentliche Schnittstelle von Implementierungsdetails trennen. Sie können Klassenmitglieder in einen Abschnitt private
werfen, aber das funktioniert nicht für andere Entitäten. (Sogar die Header/Body-Trennung ist undicht, es sei denn, Sie fügen zusätzliche Techniken wie PIMPL hinzu, also ist dieses Argument ein bisschen schwach IMO, aber wiederum würde ich in einem großen Projekt diese effiziente, wenn auch unvollkommene Methode vermissen).
Große Frage, sowieso - Sie haben erkannt, dass es etwas in Konflikt geraten mit dem C/C++ Modell zu bauen, das ich ein altes Relikt der schrecklichen Auswirkungen berücksichtigen.
Sie sollten versuchen, wie weit Sie ein "nur Kopf" -Modell schieben können (oder zumindest "fast nur Kopfzeilen", um Statik zu ermöglichen). Sie könnten ziemlich weit kommen - es wäre auch interessant von Leuten zu hören, die es versucht haben.
Es könnte einen Versuch wert sein, statische Bibliotheken zu verwenden, um Implementierungen zu trennen und zu kapseln, und ansonsten den gesamten Code in den Headern zu behalten. Ich kann ein paar Probleme damit sehen, aber es ist nicht so, dass unser aktueller Modus operandi problemlos ist.
Header-Dateien (.h) dienen dazu, die Schnittstelle zu definieren, damit Ihre Klassen und Ihr Code in anderen Übersetzungseinheiten verwendet werden können. Wenn Sie die Implementierung in die .h-Datei einfügen, erhalten Sie mehrere Kopien desselben Codes, die in jede Übersetzungseinheit kompiliert werden, die diese .h-Datei enthält. Das vereitelt den Punkt, den Code in kleine Teile zu teilen, die isoliert studiert und entwickelt werden können.
Ich denke, es könnte noch getan werden, können Sie die öffentliche Schnittstelle in die Header, die die "Implementierungsheader" enthalten, wie Boost mit den "Details" Unterordner setzen. Ohne starke Verwendung von Schnittstellen stimmt die .h/.cpp-Trennung sowieso nicht sehr gut mit der Schnittstelle/Implementierungstrennung überein. – peterchen
Sie könnte setzen Sie Ihren gesamten Code in .h-Dateien. Entgegen der landläufigen Meinung wird dies den Code in Ihren OBJ-Dateien nicht kopieren. Moderne Compiler sind viel schlauer als das.
Compilation ist etwas ein Problem. Wenn Sie 20 .h Dateien haben, die alle in main.cpp enthalten sind, dauert das Kompilieren von main.cpp eine Weile. Und es wird jedes Mal, wenn sich eine Ihrer Include-Dateien ändert, neu kompiliert, einschließlich aller 20 Dateien Ihrer Implementierung .h.
Dann gibt es Stil. Es sieht einfach falsch für mich aus. Aber das ist eine Frage der Präferenz.
Dann gibt es Referenzen. Wenn ClassA ClassB verwendet und ClassB ClassA verwendet, welchen enthält du zuerst?
Ich sehe nicht, wo moderne Compiler hinein kommen. Sobald Sie mehrere Übersetzungseinheiten haben, die Header-Dateien mit Implementierung enthalten, kopieren Sie Code in die Objektdateien. Ja, in der Theorie könnte diese Duplizierung entfernt werden, aber das müsste vom Linker und nicht vom Compiler gemacht werden. –
Ihre Annahme über Linker und Compiler-Rollen ist ziemlich veraltet. Die Erzeugung von Link-Zeit-Code wird seit einem Jahrzehnt weitverbreitet verwendet. Eine schlampige Art, das zu sagen, wäre, dass der Compiler mit LTCG nur ein schicker Präprozessor ist: Die .obj-Dateien enthalten eigentlich keinen Maschinencode. Und doppelte (und unnötige, etc, usw.) Code ist eine Gegebenheit. – martona
klingt alles sehr clever - nur schade, dass es nötig ist, um mit dem veralteten Build-Modell von C/C++ fertig zu werden! –
- 1. Warum kann ich meinen C# -Typ nicht in IronPython importieren?
- 2. Warum unterbricht @SuppressWarnings meinen Code?
- 3. Kann ich meinen Code in PLTScheme zerlegen?
- 4. Wie kann ich Emacs meinen C-Code automatisch einrücken lassen?
- 5. Warum sollte ich keine Leerzeichen in Dateinamen verwenden, wenn ich einen Code verwenden kann?
- 6. Wie kann ich ein Datenbankverbindungsobjekt in der gesamten Anwendung verwenden?
- 7. Warum kann ich nicht verhindern, dass vim meinen Code einpackt?
- 8. Wie kann ich meinen SQL-Code optimieren?
- 9. Wo kann ich meinen Ruby-Code kompilieren?
- 10. PyQt4: Ich kann meinen Dialog nicht öffnen, wenn ich meinen ersten Code schreibe
- 11. Wie kann ich meinen JS-Code verbessern?
- 12. Schwierigkeiten im Verständnis in c-Code haben
- 13. Warum kann ich meinen IntVar nicht einstellen?
- 14. Warum kompiliert Xcode meinen gesamten Code zweimal, was zu Linkerfehlern für irgendwelche Globalen führt?
- 15. Warum kann ich SynchronizedCollection nicht verwenden, wenn ich System.Collections.Generic einschließe?
- 16. Warum bekomme ich `java.lang.NoClassDefFoundError: scala/Function1`, wenn ich meinen Code in ScalaIDE ausführe?
- 17. Wie kann ich Eclipse-Code-Stil verwenden, um meinen Code in Wordpress zu markieren
- 18. Warum verwenden Fremdschlüssel zu meinen Tabellen, wenn ich das mit SQL-Joins erreichen kann?
- 19. Warum verwenden wir Cookies in Asp.net, wenn wir Sitzungen haben?
- 20. Erzwingen meinen Code meine Erweiterungsmethode verwenden
- 21. Was nutzt meinen gesamten Speicher? [__MutationMarker__]
- 22. Wenn ich meinen bool new_block auf FALSE setze, tut der Code nichts (C)
- 23. Kann ich einen Funktionsnamen in meinen jquery-Plugin-Parametern verwenden?
- 24. Wie kann ich diesen Code nicht in meinen Modellen wiederholen?
- 25. Warum kann ich in C# Operatoren für Generika verwenden?
- 26. Warum bricht mein Controller meinen Code?
- 27. Warum kann ich $ scope.feedback.myChannel nicht in meinem Controller verwenden, wenn ich ihn in meiner HTML-Seite verwenden kann?
- 28. kann ich meinen vorhandenen Code in Funktion einpacken?
- 29. Wie kann ich C# -Code in HTML verwenden?
- 30. Kann ich Debugger-Anweisungen in meinen Groovy-Code einfügen?
+1 für den Aufruf von C/C++ Build/Link-Modell, das wirklich ziemlich düster ist –