Wenn Sie Ihren Code in mehrere Dateien aufteilen, was genau sollte in eine .h-Datei und was in eine .cpp-Datei passen?
c++
header-files
Enrico Tuvera Jr.
quelle
quelle
.hpp
Datei gespeichert werden, während C-Deklarationen in einer.h
Datei gespeichert werden. Dies ist sehr hilfreich beim Mischen von C- und C ++ - Code (z. B. Legacy-Module in C).Antworten:
Header-Dateien (
.h
) sollen die Informationen bereitstellen, die in mehreren Dateien benötigt werden. Dinge wie Klassendeklarationen, Funktionsprototypen und Aufzählungen werden normalerweise in Header-Dateien gespeichert. Mit einem Wort "Definitionen".Codedateien (
.cpp
) sollen die Implementierungsinformationen bereitstellen, die nur in einer Datei bekannt sein müssen. Im Allgemeinen gehören Funktionskörper und interne Variablen, auf die andere Module niemals zugreifen sollten / werden, zu den.cpp
Dateien. Mit einem Wort "Implementierungen".Die einfachste Frage, die Sie sich stellen müssen, um festzustellen, was wohin gehört, lautet: "Wenn ich dies ändere, muss ich dann den Code in anderen Dateien ändern, damit die Dinge wieder kompiliert werden?" Wenn die Antwort "Ja" lautet, gehört sie wahrscheinlich in die Header-Datei. Wenn die Antwort "Nein" lautet, gehört sie wahrscheinlich in die Codedatei.
quelle
export
). Der einzige Weg um # 1 herum ist PIMPL. # 2 wäre möglich, wennexport
es unterstützt würde und möglicherweise mit c ++ 0x undextern
Vorlagen möglich wäre. IMO, Header-Dateien in C ++ verlieren viel von ihrer Nützlichkeit.Tatsache ist, dass dies in C ++ etwas komplizierter ist als die C-Header- / Quellorganisation.
Was sieht der Compiler?
Der Compiler sieht eine große Quelldatei (.cpp), deren Header ordnungsgemäß enthalten sind. Die Quelldatei ist die Kompilierungseinheit, die in eine Objektdatei kompiliert wird.
Warum sind Header notwendig?
Weil eine Kompilierungseinheit möglicherweise Informationen über eine Implementierung in einer anderen Kompilierungseinheit benötigt. So kann man beispielsweise die Implementierung einer Funktion in eine Quelle schreiben und die Deklaration dieser Funktion in eine andere Quelle schreiben, die sie verwenden muss.
In diesem Fall gibt es zwei Kopien derselben Informationen. Welches ist böse ...
Die Lösung besteht darin, einige Details zu teilen. Während die Implementierung in der Quelle verbleiben sollte, muss möglicherweise die Deklaration gemeinsamer Symbole wie Funktionen oder die Definition von Strukturen, Klassen, Aufzählungen usw. gemeinsam genutzt werden.
Überschriften werden verwendet, um diese freigegebenen Details zu platzieren.
Verschieben Sie in den Header die Deklarationen darüber, was von mehreren Quellen gemeinsam genutzt werden muss
Nichts mehr?
In C ++ gibt es einige andere Dinge, die in den Header eingefügt werden könnten, da sie ebenfalls gemeinsam genutzt werden müssen:
Gehen Sie in den Header ALLES, was freigegeben werden muss, einschließlich freigegebener Implementierungen
Bedeutet das dann, dass sich Quellen in den Headern befinden könnten?
Ja. Tatsächlich gibt es viele verschiedene Dinge, die sich in einem "Header" befinden könnten (dh zwischen Quellen geteilt werden).
Es wird kompliziert und in einigen Fällen (zirkuläre Abhängigkeiten zwischen Symbolen) unmöglich, es in einem Header zu halten.
Überschriften können in drei Teile unterteilt werden
Dies bedeutet, dass Sie im Extremfall Folgendes haben könnten:
Stellen wir uns vor, wir haben ein MyObject mit Vorlagen. Wir könnten haben:
.
.
.
Beeindruckend!
Im "wirklichen Leben" ist es normalerweise weniger kompliziert. Der meiste Code hat nur eine einfache Header- / Quellorganisation mit etwas Inline-Code in der Quelle.
In anderen Fällen (Vorlagenobjekte, die sich kennen) musste ich für jedes Objekt separate Deklarations- und Implementierungsheader haben, wobei eine leere Quelle diese Header enthielt, damit ich einige Kompilierungsfehler erkennen konnte.
Ein weiterer Grund für die Aufteilung von Headern in separate Header könnte darin bestehen, die Kompilierung zu beschleunigen, die Anzahl der analysierten Symbole auf das erforderliche Maß zu beschränken und eine unnötige Neukompilierung einer Quelle zu vermeiden, die sich nur um die Vorwärtsdeklaration kümmert, wenn sich eine Implementierung einer Inline-Methode ändert.
Fazit
Sie sollten Ihre Code-Organisation so einfach wie möglich und so modular wie möglich gestalten. Fügen Sie so viel wie möglich in die Quelldatei ein. Stellen Sie in Headern nur fest, was freigegeben werden muss.
Aber an dem Tag, an dem Sie kreisförmige Abhängigkeiten zwischen Vorlagenobjekten haben, wundern Sie sich nicht, wenn Ihre Codeorganisation etwas "interessanter" wird als die einfache Header- / Quellorganisation ...
^ _ ^
quelle
Zusätzlich zu allen anderen Antworten werde ich Ihnen sagen, was Sie NICHT in eine Header-Datei einfügen: Die
using
Deklaration (das häufigste Wesenusing namespace std;
) sollte nicht in einer Header-Datei erscheinen, da sie den Namespace der Quelldatei verschmutzt, in der sie enthalten ist .quelle
using
, um Dinge in einem Header in den globalen Namespace zu bringen.static inline
in C99 verwenden würden, da dies damit zu tun hat, was passiert, wenn Sie interne Verknüpfungen mit Vorlagen kombinieren. Mit Anon-Namespaces können Sie Funktionen "ausblenden" und gleichzeitig die externe Verknüpfung beibehalten.Was zu nichts kompiliert wird (kein binärer Footprint), wird in die Header-Datei aufgenommen.
Variablen werden nicht zu nichts kompiliert, Typdeklarationen jedoch (weil sie nur beschreiben, wie sich Variablen verhalten).
Funktionen nicht, aber Inline-Funktionen (oder Makros), weil sie nur dort Code erzeugen, wo sie aufgerufen werden.
Vorlagen sind kein Code, sondern nur ein Rezept zum Erstellen von Code. so gehen sie auch in h-Dateien.
quelle
Im Allgemeinen fügen Sie Deklarationen in die Header-Datei und Definitionen in die Implementierungsdatei (.cpp) ein. Eine Ausnahme bilden Vorlagen, bei denen die Definition auch im Header enthalten sein muss.
Diese und ähnliche Fragen wurden häufig in SO gestellt - siehe Warum haben Header- und CPP-Dateien in C ++? und C ++ - Header-Dateien, z. B. Codetrennung .
quelle
Ihre Klassen- und Funktionsdeklarationen sowie die Dokumentation und die Definitionen für Inline-Funktionen / Methoden (obwohl einige es vorziehen, sie in separaten INL-Dateien abzulegen).
quelle
Hauptsächlich Header-Dateien enthalten Klassenskelett oder Deklaration (ändert sich nicht häufig)
und cpp-Datei enthält Klassenimplementierung (Änderungen häufig).
quelle
Die Header-Datei (.h) sollte für Deklarationen von Klassen, Strukturen und deren Methoden, Prototypen usw. sein. Die Implementierung dieser Objekte erfolgt in cpp.
in .h
quelle
Ich würde erwarten zu sehen:
Die wirkliche Antwort ist jedoch, was man nicht eingeben sollte:
quelle
Der Header Definiert etwas, sagt aber nichts über die Implementierung aus. (Ausgenommen Vorlagen in diesem "Metafore".
Nachdem dies gesagt wurde, müssen Sie "Definitionen" in Untergruppen unterteilen. In diesem Fall gibt es zwei Arten von Definitionen.
Jetzt spreche ich natürlich über die erste Untergruppe.
Der Header dient dazu, das Layout Ihrer Struktur zu definieren, damit der Rest der Software die Implementierung verwenden kann. Vielleicht möchten Sie es als "Abstraktion" Ihrer Implementierung sehen, was vage gesagt wird, aber ich denke, es passt in diesem Fall ganz gut.
Wie bereits in früheren Postern erwähnt, haben Sie private und öffentliche Nutzungsbereiche und deren Überschriften deklariert. Dazu gehören auch private und öffentliche Variablen. Nun, ich möchte hier nicht auf das Design des Codes eingehen, aber Sie möchten vielleicht überlegen, was Sie in Ihre Header einfügen, da dies die Ebene zwischen dem Endbenutzer und der Implementierung ist.
quelle
quelle
Header (.h)
Körper (.cpp)
Als Faustregel setzen Sie den "freigegebenen" Teil des Moduls auf die .h (den Teil, den andere Module sehen müssen) und den "nicht freigegebenen" Teil auf die .cpp
PD: Ja, ich habe globale Variablen aufgenommen. Ich habe sie einige Male verwendet und es ist wichtig, sie nicht in den Headern zu definieren, sonst erhalten Sie viele Module, von denen jedes seine eigene Variable definiert.
EDIT: Geändert nach dem Kommentar von David
quelle