Muss die Definition (z.B. einer Klasse) in eine seperate Datei?
-
Hallo,
Ich habe mir diese Frage jetzt schon öfters gestellt:
Muss die Definition einer Klasse, Funktion außerhalb der Header Datei liegen (z.B. in einer seperaten .cpp Datei).
Ich habe in vielen Tutorials und Büchern gelesen das man das strikt trennen soll, nur habe ich nicht so richtig verstanden warum? Es ist eigentlich einfacher alles in eine Header Datei zu packen und die mit include zu includieren. Wenn es zusätzlich eine seperate .cpp Datei gibt muss diese mit angegeben werden (Projektmanagment), wobei ich da schon so manchen Fehler erlebt habe (z.B Datei wird nicht mit kompeliert).
Danke im Voraus
-
Inline Methoden (also sehr kurze Funktionen) musst du im Header implementieren, aber ansonsten solltest du die Implementierung vom Header trennen, da du ansonsten bei einer Änderung an der Klasse Zwangsweise große Teile deines Projekts neukompilieren musst, was je nach größe deines Projektes eine halbe Ewigkeit dauern kann.
Außerdem sorgst du so für Probleme mit virtuellen Funktionen, da viele Compiler das vtable immer in der Code Datei erstellen in der die Klasse implementiert wird und wenn alles im Header steht, gibt es keine Code Datei und der Compiler kann kein vtable anlegen und du hast ein Problem.
wobei ich da schon so manchen Fehler erlebt habe (z.B Datei wird nicht mit kompeliert).
Ja, dass ist deine Aufgabe dich darum zu kümmern oder du brauchst eine IDE die das für dich macht.
-
flammenvogel schrieb:
Muss die Definition einer Klasse, Funktion außerhalb der Header Datei liegen (z.B. in einer seperaten .cpp Datei).
Nein, muss nicht. C++ interessiert eigentlich überhaupt nicht, wo irgendwelche Definitionen liegen. Wichtig ist, dass Funktionsdefinitionen (nicht-inline und nicht-template) und Definitionen von extern sichtbaren Variablen (inkl. statische Membervariablen) exakt einmal im ganzen Programm vorkommen. Schreibst du solche Definitionen in Header, kann es leicht zu Mehrfachdefinitionen kommen, weil der Header vielleicht in verschiedenen cpp-Files eingebunden wird.
Es ist eigentlich einfacher alles in eine Header Datei zu packen und die mit include zu includieren.
Stell dir das mal mit richtig großen Programmen vor ... der Compiler müsste alles im Speicher halten, und bei jeder kleinen Änderung müsste alles neu übersetzt werden. Deshalb gibt es getrennte Übersetzung.
-
Also ich persönlich schreibe keine Projekte die mit den eigenen include Sachen größer als 500 - 1000 Zeilen sind. Die Klassen die ich schreibe (und dann in eigene Dateien auslagere) sind eigentlich fertig (es ändert sich nichts mehr -> ganz selten).
Das Problem mit der mehrfach Definition hast du bei der Dekleartion doch auch du musst eben ein mehrfach include schutz in die Datei bauen.
Gibt es sonst noch irgendwelche Gründe?
-
egal, ob du für den hausgebrauch oder die schule kleine projekte machst..und die "irgendwie" laufen...
ich würde mir programmieren gleich im hinblick auf "perspektive" aneignen.
-
kingruedi schrieb:
Inline Methoden (also sehr kurze Funktionen) musst du im Header implementieren,
Die kann man doch genauso gut in einer cpp definieren und mit dem keyword "inline" kennzeichnen.
-
Die Sache ist die das ich die Dateien immer in der Projektverwaltung mit angeben muss und ich eigentlich nicht einsehe warum, so große Header Dateien habe ich nicht. Daher finde ich es nur unübersichtlicher eine Klasse mit weniger als 200 Zeilen auf mehrere Dateien aufzuteilen. Gibt es außer dem Stil jetzt noch irgendeinen wichtigen Grund nicht alles in die Header Datei zu packen ???
-
flammenvogel schrieb:
Die Sache ist die das ich die Dateien immer in der Projektverwaltung mit angeben muss und ich eigentlich nicht einsehe warum, so große Header Dateien habe ich nicht. Daher finde ich es nur unübersichtlicher eine Klasse mit weniger als 200 Zeilen auf mehrere Dateien aufzuteilen. Gibt es außer dem Stil jetzt noch irgendeinen wichtigen Grund nicht alles in die Header Datei zu packen ???
Hast du Bashars Beitrag überhaupt gelesen?
-
Ja habe ich.
Die Frage müsste eigentlich lauten ob es doch noch irgendeinen Grund gibt der in Bashars Beitrag nicht auftaucht.
-
interpreter schrieb:
kingruedi schrieb:
Inline Methoden (also sehr kurze Funktionen) musst du im Header implementieren,
Die kann man doch genauso gut in einer cpp definieren und mit dem keyword "inline" kennzeichnen.
Wenn ich in der cpp vor der methode inline schreibe, muss ich das dann auch in der headerdatei vor der methode schreiben? Merkwürdigerweise gehen diese 3 Varianten:
header:
inline void Funktion();
cpp:
inline void Funktion();oder
header:
void Funktion();
cpp:
inline void Funktion();oder
header:
void Funktion();
cpp:
inline void Funktion();Wie ist es richtig?
-
flammenvogel schrieb:
Die Klassen die ich schreibe (und dann in eigene Dateien auslagere) sind eigentlich fertig (es ändert sich nichts mehr -> ganz selten).
gut. behalte diesen stil am besten bei. es ist ja auch naheliegend und praktisch.
es gibt nichts schlimmeres, als etwas "aus prinzip" zu machen, nur weil es in 95% aller bücher so vorgeschlagen wurde.Gibt es sonst noch irgendwelche Gründe?
wenn man zu mehreren leutchen an einem programm arbeitet, lohnt es sich oft, alle öffentlichen klassen sofort in header-dateien reinzuschreiben, damit ein jeder möglichst schnell viel fremden code benutzen kann.
-
fghfgh schrieb:
interpreter schrieb:
kingruedi schrieb:
Inline Methoden (also sehr kurze Funktionen) musst du im Header implementieren,
Die kann man doch genauso gut in einer cpp definieren und mit dem keyword "inline" kennzeichnen.
Wenn ich in der cpp vor der methode inline schreibe, muss ich das dann auch in der headerdatei vor der methode schreiben? Merkwürdigerweise gehen diese 3 Varianten:
header:
inline void Funktion();
cpp:
inline void Funktion();oder
header:
void Funktion();
cpp:
inline void Funktion();oder
header:
void Funktion();
cpp:
inline void Funktion();Wie ist es richtig?
Hilft mir da kurz wer
-
@fghfgh
Wenn alle drei Sachen funktionieren (sich kompelieren lassen). Wird wohl auch alles funktionieren.
Ich würde aber in der Dekleartion sowie in der Definition inline davor schreiben.
-
flammenvogel schrieb:
@fghfgh
Wenn alle drei Sachen funktionieren (sich kompelieren lassen). Wird wohl auch alles funktionieren.
Ich würde aber in der Dekleartion sowie in der Definition inline davor schreiben.
Aber irgendwo muss doch ein Unterschied sein, sonst würde es nicht die 3Varianten geben oder
-
header:
void Funktion();
cpp:
inline void Funktion();oder
header:
void Funktion();
cpp:
inline void Funktion();Entweder ich bin blind, oder die beiden varianten sind identisch.
-
vertausch das inline doch einfach, ich hab mich halt vertippt
, es gibt aber 3 varianten und alle funktionieren. nur warum?
-
Warum führen mehrere Straßen nach Rom. Es gibt beim Programmieren eben manchmal mehre Möglichkeiten, etwas zu lösen.
inline signalisiert dem Kompiler er soll die Funktionsaufrufe im Quelltext durch denn Quelltext der Funktion erstetzen. Wenn du dann einmal irgendwo inline hinschreibst weiß der Compiler bescheid. <- Da gibt es keinen Unterschied
-
flammenvogel schrieb:
inline signalisiert dem Kompiler er soll die Funktionsaufrufe im Quelltext durch denn Quelltext der Funktion erstetzen. Wenn du dann einmal irgendwo inline hinschreibst weiß der Compiler bescheid. <- Da gibt es keinen Unterschied
Sicher gibt es einen Unterschied.
Zum wiederholten Male: Der Compiler kann eine Funktion nur dort inline expandieren wo er die Definition der Funktion sieht. Wenn du eine Funktion also nur in einer cpp-Datei inline deklarierst, dann kann diese Funktion auch nur innerhalb dieser Datei inline expandiert werden. Unproblematisch, aber vielleicht nicht das, was gewollt war.Kommen wir also zu den möglichen Szenarien:
1. inline Deklaration im Header + Definition der Funktion im Headerinline void func() { ... } // bzw. class Foo { public: void foo() {...} // inline };
Diese Variante ist unproblematisch. Überall wo func aufgerufen werden soll ist auch die Definition von func sichtbar. Der Code kann inline expandiert werden. ODR-Verletzungen können nur auftrten, wenn mit bedingter Übersetzung rumgespielt wird.
2. inline Deklaration im Header + Deklaration im Header + Definition in cpp-Datei
// func.h inline void func(); // func.cpp #include "func.h" void func() // identisch zu inline void func { }
Diese Variante ist richtig gefährlich.
Erstmal kann func nur innerhalb von func.cpp inline expandiert werden (es sei denn irgendjemand kommt auf die schwachsinnige Idee func.cpp zu inkludieren).
Andere Clients von func müssen func.h inkludieren und gegen func.o linken.Gleichzeit lauern hier aber ODR-Verletzungen. Da func in func.h inline deklariert wurde, darf func nun "Einmal pro Übersetzungseinheit" definiert werden. Solange jede Definition tokenweise identisch ist.
Das Blöde ist, dass viele Compiler/Linker-Kombinationen die letzte Einschränkung nicht prüfen und man so schnell undefiniertes Verhalten bekommt:// func.h inline void func(); // func.cpp #include "func.h" void func() // identisch zu inline void func { } // main.cpp #include "func.h" void func() { cout << "Hallo undefiniertes Verhalten!" << endl; } int main() { func(); }
main.cpp und func.cpp können da func in func.h inline deklariert wurde zusammen zu einem Programm gelinkt werden. func darf sowohl in main, als auch in func.cpp aufgerufen werden, da beide Dateien die Definition der Inline-Funktion enthalten.
Dummerweise unterscheiden sich die beiden Definitionen von func. Ergebnis: undefiniertes Verhalten.3. normale Deklaration im Header + inline Definition in cpp-Datei
// func.h void func(); // func.cpp inline void func() {}
Diese Variante ist ebenfalls problematisch.
func kann wieder nur innerhalb von func.cpp inline generiert werden.
Gleichzeitig führt *jeder* Aufruf von func außerhalb von func.cpp zu undefiniertem Verhalten.
Der Standard schreibt vor, dass eine inline-Funktion nur dort aufgerufen werden darf, wo dessen Definition sichtbar ist. Andernfalls ist das Verhalten undefiniert. Sollte func außerhalb von func.cpp erneut definiert werden, bekommt man wiederum undefiniertes Verhalten, falls die neue Definition nicht tokenweise identisch mit der von func.cpp ist.Fazit:
* Inline kann nur bei der Deklaration, nur bei der Definition oder sowohl bei der Deklaration als auch der Definition einer Funktion auftreten.* Eine inline-Funktion darf nur dort aufgerufen werden, wo ihre Definition sichtbar ist.
* Auf der sicheren Seite ist man bei inline Funktionen nur, wenn man selbige in einem Header definiert. Wo man dann das inline hinschreibt ist wurscht.
* Merkregel: Definiere inline-Funktionen immer in Header-Dateien.