C ++ Header-Reihenfolge

Welche Reihenfolge sollten Header in einer Header / cpp-Datei deklariert werden? Offensichtlich sollten diejenigen, die von nachfolgenden Headern benötigt werden, früher sein und klassenspezifische Header sollten sich im cpp-Bereich befinden, nicht im Header-Bereich, aber gibt es eine festgelegte Reihenfolge / Best Practice?

In einer Header-Datei müssen Sie ALLE Header einfügen, um sie kompilierbar zu machen. Und vergessen Sie nicht, Forward-Deklarationen statt einiger Header zu verwenden.

In einer Quelldatei:

  • Entsprechende Header-Datei
  • notwendige Projektheader
  • Header von Drittanbieterbibliotheken
  • Standardbibliotheks-Header
  • System-Header

In dieser Reihenfolge werden Sie keine Ihrer Header-Dateien verpassen, die vergessen haben, Bibliotheken selbst einzubinden.

Gute Praxis: Jede .h-Datei sollte eine .cpp haben, die diese .h vor allem anderen enthält. Dies beweist, dass jede .h-Datei als erstes angegeben werden kann.

Auch wenn der Header keine Implementierung erfordert, erstellen Sie eine .cpp-Datei, die nur diese .h-Datei und sonst nichts enthält.

Das bedeutet dann, dass Sie Ihre Frage beliebig beantworten können. Es spielt keine Rolle, in welche Reihenfolge Sie sie aufnehmen.

Für weitere gute Tipps, versuchen Sie dieses Buch: Large-Scale C ++ Software Design – es ist schade, dass es so teuer ist, aber es ist praktisch eine Überlebensanleitung für C ++ – Quellcode-Layout.

In Header-Dateien tendiere ich dazu, zuerst Standard-Header zu setzen, dann meine eigenen Header (beide Listen werden alphabetisch sortiert). In Implementierungsdateien gebe ich zuerst den entsprechenden Header (falls vorhanden), dann Standard-Header und andere Abhängigkeits-Header ein.

Die Reihenfolge ist von geringer Bedeutung, außer wenn Sie Makros und #define . In diesem Fall müssen Sie prüfen, ob ein von Ihnen definiertes Makro ein zuvor enthaltenes Makro nicht ersetzt (außer natürlich, wenn Sie das möchten).

In Bezug auf diese Aussage

Diejenigen, die von nachfolgenden Headern benötigt werden, sollten früher sein

Eine Kopfzeile sollte nicht darauf angewiesen sein, dass andere Kopfzeilen davor enthalten sind! Wenn es Header benötigt, enthält es nur diese. Header-Wächter verhindern mehrfache Aufnahme:

 #ifndef FOO_HEADER_H #define FOO_HEADER_H ... #endif 

BEARBEITEN

Seit ich diese Antwort geschrieben habe, habe ich die Art und Weise geändert, wie ich die Include-statementen in meinem Code anordne. Jetzt versuche ich, Header immer in der Reihenfolge der Standardisierung zu setzen, so dass die Header meines Projekts zuerst kommen, gefolgt von Headers von Drittanbieter-Bibliotheken, gefolgt von Standard-Headern.

Wenn zum Beispiel eine meiner Dateien eine Bibliothek verwendet, die ich geschrieben habe, Qt, Boost und die Standardbibliothek, werde ich die Includes wie folgt bestellen:

 //foo.cpp #include "foo.hpp" #include  // other headers related to my_library #include  // other Qt headers #include  // Boost is arguably more standard than Qt // other boost headers #include  // other standard algorithms 

Der Grund, warum ich das tue, ist, fehlende Abhängigkeiten in meinen eigenen Headern zu finden: my_library.hpp wir zum Beispiel an, dass my_library.hpp std::copy , aber nicht . Wenn ich es nach in foo.cpp , wird diese fehlende Abhängigkeit unbemerkt foo.cpp . Im Gegensatz dazu wird der Compiler mit der Reihenfolge, die ich gerade vorgestellt habe, beklagen, dass std::copy nicht deklariert wurde, was es mir erlaubt, my_library.hpp zu korrigieren.

In jeder “library” -Gruppe versuche ich, die include-statementen alphabetisch sortiert zu halten, um sie leichter finden zu können.

Nebenbei bemerkt, ist es auch eine gute Übung, die Abhängigkeit zwischen den Header-Dateien maximal zu begrenzen. Dateien sollten so wenig Header wie möglich enthalten, insbesondere Header-Datei. In der Tat, je mehr Header Sie hinzufügen, desto mehr Code muss neu kompiliert werden, wenn sich etwas ändert. Eine gute Möglichkeit, diese Abhängigkeiten zu begrenzen, besteht darin, die Vorwärtsdeklaration zu verwenden, die in Headerdateien häufig ausreichend ist (siehe Wann kann ich eine Forward-Deklaration verwenden? ).

Google C ++ Style Guide, Namen und Reihenfolge der Includes :

In dir / foo.cc, deren Hauptzweck es ist, das Zeug in dir2 / foo2.h zu implementieren oder zu testen, müssen Sie Ihre Includes wie folgt bestellen:

  • dir2 / foo2.h (bevorzugter Ort – Details siehe unten).
  • C Systemdateien.
  • C ++ Systemdateien.
  • Die Dateien anderer Bibliotheken .h.
  • Die Dateien Ihres Projekts .h.

Ich habe sie in alphabetischer Reihenfolge sortiert (leichter zu finden)

Das “Wie” ist nicht offensichtlich, aber das “Was” ist. Ihr Ziel ist es, sicherzustellen, dass die Reihenfolge, in der Sie Header-Dateien einfügen, nie eine Rolle spielt (und ich meine “NIEMALS!”).

Eine gute Hilfe ist es zu testen, ob Header-Dateien beim Erstellen von cpp-Dateien (eine für jede Header-Datei) kompilieren, die nur eine von ihnen enthalten.

Für .cpp-Dateien sollten Sie den Header der class oder das, was Sie zuerst implementieren, einschließen, damit Sie den Fall erfassen, in dem in diesem Header einige Includes fehlen. Danach neigen die meisten Codierungsrichtlinien dazu, zuerst die System-Header, dann die zweiten Projekt-Header zu verwenden, zum Beispiel den Google C ++ Style Guide .

Es ist eine Abhängigkeit Sache und es hängt weitgehend davon ab, was Sie in unseren Kopfzeilen setzen. Eine Tatsache ist, dass Sie wirklich berüchtigt sein können und minimieren, um Ihre Includes streng zu halten, aber Sie werden schließlich in ein Szenario geraten, in dem Sie Inklusionswächter benutzen werden.

 #ifndef MY_HEADER_H #define MY_HEADER_H //... #endif 

Das Problem ist am Anfang nicht so offensichtlich, aber mit der Komplexität Ihrer Software wachsen auch Ihre Abhängigkeiten. Sie können es gut machen und schlau sein, aber größere C ++ – Projekte sind im Allgemeinen mit Includes gespickt. Sie können es versuchen, aber Sie können nur so viel tun. Also sei fleißig und denke über deine includes nach, JA! Aber Sie werden sicherlich zyklische Abhängigkeiten haben, und deshalb brauchen Sie Inklusionswächter.

Wenn eine Kopfzeile andere Kopfzeilen benötigt, werden sie nur in diese Kopfzeile aufgenommen.

Versuchen Sie, Ihren Code so zu strukturieren, dass Sie pointers oder Referenzen übergeben und deklarieren, wo Sie können.

In der Implementierung sollte dann der Header, der ihn definiert, zuerst aufgelistet werden (außer in Visual Studio, wenn Sie pch verwenden, dann würde stdafx zuerst gehen).

Ich liste sie im Allgemeinen auf, wie ich brauche.

Ich habe die folgende Konvention am nützlichsten gefunden:

module.cpp:

 // this is the header used to trigger inclusion of precompiled headers #include  // this ensures that anything that includes "module.h" works #include "module.h" // other headers, usually system headers, the project 

Wichtig ist, den Header des Moduls als ersten nicht vorkompilierten Header zu setzen. Dies stellt sicher, dass “module.h” keine unerwarteten Abhängigkeiten hat.

Wenn Sie an einem großen Projekt mit langsamen Zugriffszeiten arbeiten, habe ich festgestellt, dass dieser Stil die Build-Zeiten verringert:

module.cpp:

 // this is the header used to trigger inclusion of precompiled headers #include  // this ensures that anything that includes "module.h" works #include "module.h" // other headers, usually system headers, the project #if !defined _OTHER_MODULE_GUARD_ #include "other_module.h" #endif #if !defined _ANOTHER_MODULE_GUARD_ #include "another_module.h" #endif 

Es ist ein wenig ausführlich, aber spart Festplattensuche, da die Kopfzeile nicht gesucht / geöffnet wird, wenn sie bereits enthalten ist. Ohne die #ifdef sucht der Compiler nach der Header-Datei und öffnet sie, #ifdef die gesamte Datei, um zu enden, #ifdef die gesamte Datei entfernt wird.