Code in h-Datei und cpp-Datei aufteilen
-
Hi,
ich habe ein paar Verständnisfragem bei denen mir hoffentlich jemand behliflich sein kann.
kann mir jemand erklären wieso es üblich ist den code (z.B. einer Klasse) in zwei unterschiedliche Dateien. zu schreiben?
Also in der h-Datei schreibe ich die Deklarationen der Klasse und in die cpp-Datei die Implementierungen dazu. Aber wieso sollte ich nicht beides in die h-Datei schreiben?
Als Grund habe ich gelesen, dass ich so die Abhängigkeiten minimieren, aber durch einbinden einer h-Datei müssen ja auch die Implementierungen dazu gebunden werden.
Sind die #includes wie z.B. #include <string> auch in h- und cpp-Dateien aufgeteilt?
Was mich auch noch interessieren würde ist die Verwendung von "Schnittstellen"-Klassen. In dieser Klasse deklariere ich ja nur ausschließlich abstrakte Funktionen.
Da ich hiervon kein Objekt instanziieren kann ist eine solche Schnittstellen-Klasse doch eigentlich nicht notwendig, da ich die eigentliche Deklaration ja nochmals in der werbenden Klasse deklariere?
Hoffe meine Fragen sind klar geworden.
Danke schon mal.
-
Du kannst alles in einzelne Headerateien schreiben und in einer Datei (nennen wir sie main.cpp) einbinden. Dann würdest du die main.cpp übersetezen und hättest dein Programm. Jetzt stell dir vor, es sind 60 000 Zeilen Code. Bei jeder noch so kleinen Änderung muss alles neu übersetzt werden. Zerlegst du alles in kleine Häppchen, muss oft nur ein kleiner Teil neu übersetzt werden und du bist viiiiiieeeeel schneller fertig. Die Dateinamen sind dabei nur Konvention, sie könnten auch .tim und .struppi heißen.
-
Die Schnittstellen-Klasse ist doch notwendig. Wenn die Schnittstellen-Klasse z.B. A heisst und ich davon eine Klasse B und C ableite dann kann ich schreiben:
A *a[2];
a[0]=new B;
a[1]=new C;a[0]->irgeneineFunktion();
Also ich habe ein Array aus Basisklassen Zeiger (a[2]) und je nachdem auf welche Klasse ein Basisklassenzeiger zeigt (auf B oder auf C) dessen Funktion wird aufgerufen. Also wenn ich "irgeneineFunktion()" in B und in C nochmals deklariere und natürlich definiere, dann wird automatisch die Funktion aufgerufen auf die der Basisklassenzeiger zeigt. Bei a[0]->irgendeineFunktion() wird die von B und bei a[1]->irgendeineFunktion() wird die von C aufgerufen. Unter "dynamische Bindung" sollte man im Internet zu diesem Thema etwas finden.
-
Torben16 schrieb:
Also in der h-Datei schreibe ich die Deklarationen der Klasse und in die cpp-Datei die Implementierungen dazu. Aber wieso sollte ich nicht beides in die h-Datei schreiben?
Kann man machen und muss man sogar machen bei Template Klassen oder Template Memberfunktionen.
Torben16 schrieb:
Als Grund habe ich gelesen, dass ich so die Abhängigkeiten minimieren, aber durch einbinden einer h-Datei müssen ja auch die Implementierungen dazu gebunden werden.
Das mit den Abhängigkeiten stimmt. Stelle dir vor du hast zwei Klassen Vector2D und Vector3D für 2- und 3-dimensionale Vektoren und du möchtest eine Funktion einbauen um zwischen beiden Klassen zu konvertieren. Das könnte dann irgendwie so aussehen:
class Vector2D { float x, y; //... Vector3D to3D(float z) { return Vector3D(x, y, z); } }; class Vector3D { float x, y, z; //... Vector2D to2D() { return Vector2D(x, y); } };Jetzt hast du einen Teufelskreis weil keine Klasse ohne die andere compiliert. Auflösen kann man das indem man eine forward declaration für die jeweils andere Klasse macht und im Header die Funktionen nur deklariert. Die Implementierung kommt dann in der cpp-Datei, wo dann beide Klassen bekannt sind.
Torben16 schrieb:
Sind die #includes wie z.B. #include <string> auch in h- und cpp-Dateien aufgeteilt?
Prinzipiell schon aber bei deinem Beispiel mit std::string könnte vielleicht sogar alles nur im Header stehen weil es eine Template Klasse ist. Bei iostream haben wir zwar auch Template Klassen aber es gibt sicher ein paar Kernfunktionen die nicht im Header stehen und später dazu gelinked werden. Die iostream.cpp kriegt man als normaler Benutzer nie zu Gesicht. Außer vielleicht wenn man sich seinen Compiler selbst compiliert.
Torben16 schrieb:
Was mich auch noch interessieren würde ist die Verwendung von "Schnittstellen"-Klassen. In dieser Klasse deklariere ich ja nur ausschließlich abstrakte Funktionen.
Dadurch kann man einfach ein Interface festlegen und Klassen die davon erben müssen die Funktionen implementieren. In einer Grafikengine könnte es zum Beispiel ein Interface geben für alle Grafikobjekte. Ein Grafikobjekt zeichnet sich dann dadurch aus, dass es z.B. eine Position hat und eine Funktion draw(). In deinem Code könntest du dann alle Grafikobjekte in einer Liste speichern und alle der Reihe nach zeichnen. Was für eine Klasse da letztendlich hinter steht ist dann egal.
-
siffkroete schrieb:
Die Schnittstellen-Klasse ist doch notwendig. Wenn die Schnittstellen-Klasse z.B. A heisst und ich davon eine Klasse B und C ableite dann kann ich schreiben:
A *a[2];
a[0]=new B;
a[1]=new C;a[0]->irgeneineFunktion();
Also ich habe ein Array aus Basisklassen Zeiger (a[2]) und je nachdem auf welche Klasse ein Basisklassenzeiger zeigt (auf B oder auf C) dessen Funktion wird aufgerufen. Also wenn ich "irgeneineFunktion()" in B und in C nochmals deklariere und natürlich definiere, dann wird automatisch die Funktion aufgerufen auf die der Basisklassenzeiger zeigt. Bei a[0]->irgendeineFunktion() wird die von B und bei a[1]->irgendeineFunktion() wird die von C aufgerufen. Unter "dynamische Bindung" sollte man im Internet zu diesem Thema etwas finden.
Nein, du sprichst von etwas komplett anderem.