Angenommen, ich besitze eine Datei X.h, die eine Klasse X definiert, deren Methoden in X.cc. implementiert sind. Die Datei X.h enthält eine Datei Y.h, weil sie Y benötigt, um die Klasse X zu definieren. In X.cc können wir uns beziehen zu Y, weil X.h Y.h. Sollte ich Y.h noch in X.cc aufnehmen?
Ich verstehe, dass ich nicht muss und ich kann mich auf Header-Wachen verlassen, um mehrfache Einschlüsse zu verhindern. Aber auf der einen Seite macht die Einbeziehung von Y.h X.cc etwas unabhängiger von X.h (kann nicht sein natürlich völlig unabhängig). Was ist die akzeptierte Praxis?
Ein weiteres Beispiel: include <iostream>
in beiden .h und .cc Dateien. Ich sehe einige Leute das machen
und einige nicht.
Sei minimal. Ziehen Sie in Headern Vorwärtsdeklarationen zu vollständigen Definitionen vor. Verwenden Sie beispielsweise iosfwd
anstelle von ostream
.
Das heißt, X.h und X.cc repräsentieren die gleiche logische Einheit. Wenn sich Ihre Abhängigkeit von Y.h jemals geändert hat (z. B. in eine Forward-Deklaration umgewandelt wurde), würden Sie die Klasse trotzdem ändern. Sie können #include "Y.h"
also zu Recht auf X.cc verschieben.
Mit anderen Worten, X.cc und X.h gehen Hand in Hand. X.cc kann zuverlässig annehmen, was in X.h. Es ist also nicht notwendig, etwas wieder aufzunehmen, wenn X.h dies tut.
Abhängigkeiten, bei denen Sie es trotzdem einfügen, kommen mit Ressourcen anderen vor als Ihre eigenen. Zum Beispiel, wenn Sie Z.h benötigen, würden Sie es einschließen, selbst wenn Y.h tut. X.h kann den Inhalt von Y.h nicht zuverlässig annehmen, da X.h nicht mit Y.h geht, sondern es verwendet.
Ich würde vorschlagen, das Header-Include für Y in X.cc einzuschließen, auch wenn es redundant erscheint. Es bietet Ihnen den Vorteil, dass Ihre Abhängigkeiten sehr explizit sind.
Als eine verwandte Anmerkung sollten Sie immer den zugehörigen Header für eine cpp-Datei als erste # include'd-Datei einschließen. (Das erste Include in X.cpp sollte X.h sein) Dies garantiert, dass der Header die richtigen Dateien enthält, um seine eigenen Abhängigkeiten aufzulösen, andernfalls könnten Sie sich versehentlich auf die Reihenfolge der Includes in Ihrer Quelldatei verlassen.
Ich bin mir nicht sicher, warum das eine gute Übung wäre.
Andererseits ist nicht einschließlich unnötiger Dateien in X.h
etwas, das ich für eine sehr gute Praxis halte.
Zum Beispiel im folgenden Szenario:
Es wäre ausreichend, Y
zu deklarieren. Clients der Klasse X
müssen nicht die Kosten für die Headerdatei für Y
übernehmen:
Dies ist in der Header-Datei möglich, weil die Deklaration der Klasse X
keine spezifischen Details über Y
erfordert (z. B. die Größe einer Instanz); Nur das Y
ist eine Klasse. Darüber hinaus behandeln Clients der Klasse X
niemals den Typ Y
, da sie nicht Teil der öffentlichen Schnittstelle von X
sind.
Bei großen Projekten kann das Vermeiden unnötiger Include-Direktiven in Header-Dateien die Build-Zeiten erheblich verbessern.
Es kann auch vermieden werden, den Namensraum von Benutzern Ihrer Klasse mit Symbolen aus Ihren privaten / Implementierungsklassen zu verschmutzen.
Ich denke, du solltest. Wenn Ihr Code wächst und einige Implementierungen sich ändern, werden einige aus einer Header-Datei entfernt, die in einer anderen Header-Datei enthalten ist, die in einer Header-Datei enthalten ist ... Es könnte wirklich fies werden, herauszufinden, warum etwas nicht zu tun hat Änderungen, die Sie (oder jemand anderes) vorgenommen haben, funktionieren nicht mehr.
In Ihrem Beispiel würde ich X.h nur in X.cc einschließen, um die Anzahl der Includes zu reduzieren. Ja, in dem allgemeineren Fall, in dem Sie A.cc einschließlich Xh haben, und als Nebeneffekt in der Lage ist, Zeug in Yh zu referenzieren, müssen Sie Yh manuell hinzufügen, weil Sie es zuvor nicht hinzugefügt haben . Zumindest wird der Compiler auf Ihrem Fall sein und Sie daran erinnern.
Im Falle von <iostream>
brauchen Sie es, wenn Sie es brauchen, ob in einer Header-Datei oder in einem Modul.
#include
-Anweisungen in Header-Dateien können die Übersetzungszeiten erhöhen. Für Spielzeuganwendungen oder große Systeme mit nur einer Abhängigkeit, wie Sie es beschreiben, wird dies kein Problem darstellen. Aber wenn Ihre Anwendung wächst, werden auch die Kompilierungszeiten zunehmen. Eine Auflösung unter MSVC besteht darin, vorkompilierte Header zu verwenden (was ihre eigenen Kopfschmerzen mit sich bringt) oder alle #include
-Anweisungen in Headern zu eliminieren. Letzteres ist mein Standardansatz, und ich versuche zuerst, wo nötig Vorwärtsdeklarationen zu verwenden:
Wenn die Verwendung von Forward-Deklarationen nicht möglich ist, denken Sie daran, dass #include
nichts anderes tut, als den Inhalt der angegebenen Datei an diesen Punkt zu bringen. Dies kann genauso einfach aus der cc-Datei wie aus der Kopfzeile erfolgen:
Tags und Links c++ include header-files