Ich habe eine Frage bezüglich "best-practice" beim Einschließen von Kopfzeilen.
Offensichtlich schützen Wächter uns davor, mehrere Includes in einem Header oder einer Quelldatei zu haben. Daher lautet meine Frage, ob es für Sie vorteilhaft ist, alle erforderlichen Header in einer Kopf- oder Quelldatei aufzunehmen, selbst wenn einer der Header enthalten ist enthält bereits einen der anderen Includes. Die Begründung dafür wäre, dass der Leser alles, was für die Datei benötigt wird, sehen kann, anstatt andere Header zu durchsuchen.
Beispiel: Nehmen Sie an, dass Wächter verwendet werden:
%Vor%.
%Vor%Wenn ein Header in der Header-Datei nicht benötigt wird, aber in der zugehörigen Quelldatei benötigt wird, fügen Sie ihn in den Header oder die Quelle ein?
In Ihrem Beispiel sollte bar.h # blah.h. Auf diese Weise wird jemand, der foo so modifiziert, dass er kein Blah braucht, die Bar nicht brechen.
Wenn bla.h in foo.c gebraucht wird, aber nicht in foo.h, dann sollte es nicht in foo.h enthalten sein. Viele andere Dateien können foo.h # enthalten, und mehr Dateien können sie enthalten. Wenn Sie blah.h in foo.h einschließen, dann machen Sie all diese Dateien unnötig abhängig von blah.h. Unnötige Abhängigkeiten verursachen viele Kopfschmerzen:
Die Grundregel lautet: #include
alle Header, die Sie tatsächlich in Ihrem Code verwenden. Also, wenn wir reden:
Wo bar.h
Werkzeuge aus der Kopfzeile zweimal verwendet, dann sollten Sie #include
it, auch wenn Sie es nicht unbedingt müssen. Auf der anderen Seite, wenn bar.h
keine Funktionen von utilities.h
benötigt, dann, auch wenn foo.h
es enthält, nicht #include
it.
Der Header für eine Quelldatei sollte die Schnittstelle definieren, die die Benutzer des Codes genau verwenden müssen. Es sollte alles enthalten, was sie brauchen, um die Schnittstelle zu benutzen, aber nichts extra. Wenn sie die von xyz.cpp zur Verfügung gestellte Einrichtung benötigen, benötigt der Benutzer nur #include "xyz.h"
.
Wie 'xyz.h' bietet, dass die Funktionalität weitgehend dem Implementierer von 'xyz.h' zur Verfügung steht. Wenn es Einrichtungen benötigt, die nur spezifiziert werden können, indem ein spezifischer Header eingefügt wird, sollte 'xyz.h' diesen anderen Header enthalten. Wenn es vermieden werden kann, eine bestimmte Kopfzeile (durch Vorwärtsdefinition oder andere saubere Mittel) einzubeziehen, sollte dies geschehen.
Im Beispiel würde meine Codierung wahrscheinlich davon abhängen, ob die Kopfzeile 'foo.h' von demselben Projekt gesteuert wurde wie die Kopfzeile 'blah.h'. Wenn ja, würde ich das explizite zweite Include wahrscheinlich nicht machen; Wenn nicht, könnte ich es einschließen. Die obigen Aussagen sollten mich jedoch dazu zwingen, zu sagen "Ja, schließen Sie" foo.h "ein, nur für den Fall".
Zu meiner Verteidigung glaube ich, dass der C ++ - Standard die Einbeziehung eines beliebigen C ++ - Headers in andere - wie von der Implementierung gefordert - erlaubt; Dies könnte als ähnlich angesehen werden. Das Problem ist, dass, wenn Sie nur 'bar.h' einschließen und dennoch Funktionen von 'blah.h' verwenden, wenn 'bar.h' geändert wird, weil sein Code nicht mehr 'blah.h' benötigt, dann der Code des Benutzers, der verwendet, um (zufällig) zu kompilieren, schlägt fehl.
Wenn der Benutzer jedoch direkt auf Einrichtungen von "blah.h" zugreift, sollte der Benutzer "blah.h" direkt angeben. Die überarbeitete Schnittstelle zum Code in 'bar.h' benötigt kein 'blah.h' mehr, also sollte jeder Code, der nur die Schnittstelle zu 'bar.h' verwendet, noch in Ordnung sein. Aber wenn der Code auch 'blah.h' verwendet hätte, dann hätte er es direkt einfügen sollen.
Ich vermute, dass auch das Demeter-Gesetz in Betracht gezogen werden sollte - oder als solches betrachtet werden könnte. Grundsätzlich sollte "bar.h" die Header enthalten, die benötigt werden, damit es direkt oder indirekt funktioniert - und die Verbraucher von "bar.h" sollten sich nicht viel Gedanken darüber machen.
Um die letzte Frage zu beantworten: klar, Header, die von der Implementierung benötigt werden, aber nicht von der Schnittstelle benötigt werden, sollten nur im Quellcode der Implementierung enthalten sein und absolut nicht in der Kopfzeile. Was die Implementierung verwendet, ist für den Benutzer irrelevant, und die Kompilierungseffizienz und Information, die beide verbergen, verlangen, dass der Header nur die minimal notwendige Information den Benutzern des Headers verfügbar macht.
Meine Kommentare sind vielleicht keine direkte Antwort auf Ihre Frage, aber nützlich.
IOD / IOP regt an, dass weniger Header in INTERFACE-Header eingefügt werden, was die wichtigsten Vorteile bietet:
pro IOD / IOP, sollten Schnittstellen nur in .h / .hxx-Header eingefügt werden. Fügen Sie stattdessen Header in Ihre .c / .cpp ein.
Meine Regeln für Header-Dateien sind:
In der Header-Datei enthalten nur #include Klassen, die Mitglieder oder Basisklassen Ihrer Klasse sind.
Wenn Ihre Klasse Zeiger oder Referenzen verwendet, die Vorwärtsdeklarationen verwenden.
Caviat: Wenn Sie Mitglieder in der Header-Datei (Beispielvorlage) definieren, müssen Sie Plat und Clone eventuell einbeziehen (aber nur wenn unbedingt erforderlich).
Geben Sie in der Quelle Header-Dateien von der spezifischsten zur am wenigsten spezifischen Reihenfolge ein.
Aber nicht enthält alles, was Sie nicht explizit benötigen.
In diesem Fall enthalten Sie also:
Das Argument hier ist, dass, wenn Clone.h Map benötigt (und Plop benötigt map) und Sie die C ++ - Header-Dateien näher an den Anfang der Liste stellen, Sie die Tatsache verbergen, dass Clone.h Map benötigt und Sie daher nicht hinzufügen können es in Clone.h.
Verwenden Sie immer Kopfleisten
%Vor%PS: Ich schlage nicht vor, mehrere verschachtelte Namespaces zu verwenden. Ich zeige nur, wie ich es mache, wenn ich es tue. Ich stelle normal alles (außer Main) in einen Namensraum. Die Verschachtelung hängt von der Situation ab.
Vermeiden Sie die Verwendung von Deklaration.
Außer dem aktuellen Umfang der Klasse, an der ich arbeite:
Wenn Sie alles in Kopfzeilen in C ++ einfügen, kann das zu explodieren
führenBesser verkapseln und weiterleiten deklariere so viel wie möglich. Die Forward-Deklarationen liefern genügend Hinweise, was für die Verwendung der Klasse erforderlich ist. Es ist durchaus akzeptabel, dass der Standard auch darin enthalten ist (besonders Vorlagen, da sie nicht vorwärts deklariert werden können).
Tags und Links c++