Forum: PC-Programmierung Buch gesucht für C++ wegen Aufteilung in .h und .cpp


von hubert (Gast)


Lesenswert?

Hallo

Ich such ein gutes Textbuch über Programmierung in C++, das einem 
erklärt, wie man selbstgeschriebene Headerfiles organisiert, also was 
kommt in das .h , was kommt in das .cpp , in welcher Reihenfolge weden 
die #include Anweisungen in die einzelnen Dateien gesetzt und wie 
verdaut der Compiler bzw. Linker das ganze.

Tips, wie man es macht hab ich schon ein paar gelesen, aber ich würde 
das Ganze gerne insgesamt verstehen.

Bücher in englisch sind mir genauso recht, da ich englische Originale 
den übersetzten Versionen vorziehe.

Vielen Dank dafür

von Klaus W. (mfgkw)


Lesenswert?

Wahrscheinlich findest du dazu mehr in jedem C-Buch.
Der Unterschied ist minimal.
In C immer und in C++ weitestgehend ist es so, daß alle Deklarationen
in die .h kommen und die Definitionen in die .c - und zwar
gleichermaßen für Funktionen wie für globale Variablen.
Typdefinitionen und Makros landen in der .h, wenn sie in mehreren
Quelltexten genutzt werden.

In C++ kommt inline dazu, sei es explizit oder bei innnerhalb
von class{ ... } definierten Methoden implizit.
Dann stehen auch diese Methoden (also ggf. mit der gesamten
class{ ... }) in der .h.

Vielleicht reicht dir das schon: 
http://www.wachtler.de/ck/16_Aufteilung_mehrere_Quell.html

von tom (Gast)


Lesenswert?

versuchs mal mit:

"C - A Software Engineering Approach"

von P. Darnell

gruss, tom.

von Karl H. (kbuchegg)


Lesenswert?

Im Grunde ist es sehr einfach:

Du teilst dein Projekt in Module ein. Ein Modul ist eine Einheit, die 
einen bestimmten Themenkreis bearbeitet. Wie zb Stringverwaltung oder 
Kundendaten oder was auch immer.

Dann überlegst du, welche Teile deines Moduls den Verwender des Moduls 
interessieren, welche Datentypen muss der kennen wenn das Modul 
beispielsweise irgendwelche Strukturen oder Klassen definiert, welche 
Funktionen muss ein Verwender benutzen können, welche globalen Variablen 
muss ein Verwender sichtbar und zugreifbar haben.

All das kommt ins Header File.

Alles andere kommt ins cpp-File (oder C File, das Prinzip ist dasselbe).

Dazu überlegt man noch, welche weiteren Includes jeweils nötig sind, 
damit das Header File bzw cpp-File in sich vollständig ist. Wird in 
einem Header File ein Datentyp 'hamstibamsti' benutzt, der nicht Teil 
dieses Moduls ist, dann setzt man einen entsprechenden Include an den 
Anfang. Einfach nach der Regel vorgehen: Der Compiler arbeitet den Code 
von oben nach unten ab und verwendet werden kann nur das was bereits 
bekannt ist. Ein Datentyp "hamstibamsti" muss also deklariert werden ehe 
er das erstmal zb in einer Klasse benutzt werden kann. Daher muss der 
entsprechende #include vor der verwendenden Klassendeklaration kommen.

Im Grossen und Ganzen wars das auch schon.

Der eigentliche Knackpunkt am Ganzen liegt ganz woanders: Wie komme ich 
zu einer sinnvollen Aufteilung in Module?
Manchmal ist das ganz einfach und naheliegend. Manchmal hat man mehrere 
Möglichkeiten, die sich anbieten und man muss eine auswählen und 
manchmal bietet sich zunächst scheinbar überhaupt nichts an.

Ach muss man des öfteren eine künstliche Grenze einziehen. Gesucht ist 
die goldene Mitte zwischen "Die Modularisierung ist viel zu grob und 
bringt so gut wie gar nichts" und "Die Modularisierung ist viel zu fein 
und verschleiert und verkompliziert nur alles"

Da liegt der Knackpunkt und das kann dir auch kein Buch beibringen. Am 
Anfang liegt man des öfteren schon mal daneben. Dann darf man aber auch 
keine Scheu haben, die Modularisierung noch mal zu überdenken und zu 
überarbeiten und zu sehen, ob man mit einer anderen Aufteilung die 
festgestellten Probleme besser in den Griff kriegt. Nichts ist so 
tödlich, wie die Neigung von Einsteigern, die Programmteile die sie 
schon haben als "von Gott gegeben und daher unveränderbar" anzusehen.

Genausowenig wie dir ein Buch beibringen kann, ein berühmter Maler oder 
Komponist zu werden, genausowenig kann dir ein Buch die Erfahrung geben, 
wie man Modularisierung machen kann. Es gibt Daumenregeln, aber es gibt 
kein Kochrezept, dem man einfach nur folgen muss und dann ist alles gut.

von hubert (Gast)


Lesenswert?

Also... Das was Klaus schreibt hab ich soweit verstanden. Die einzelnen 
Bereiche des Programmes kommen in verschiedene .c Dateien rein, das was 
für alle gemeinsam gebraucht wird kommt in eine .h, die dann in all die 
Module includiert wird.

Nur, wie mache ich das dann, daß mir all die verschiedenen .c dateien 
jetzt zu einem Programm zusammenkompiliert werden?

Ich sollte vielleicht dazu sagen, daß ich mit Eclipse und GCC unter 
Linux arbeite...

Danke schon mal für die ausführlichen Antworten

von Klaus W. (mfgkw)


Lesenswert?

hubert schrieb:
> Also... Das was Klaus schreibt hab ich soweit verstanden. Die einzelnen
> Bereiche des Programmes kommen in verschiedene .c Dateien rein, das was
> für alle gemeinsam gebraucht wird kommt in eine .h, die dann in all die
> Module includiert wird.

Jein.

Bei kleineren/mittleren Projekten kann man es so machen.
Es ist aber oft ein Zeichen von Planlosigkeit...

Meist läuft es auf folgende Regeln hinaus:

- Das gesamte Programm besteht aus verschiedenen Modulen, die
  entweder unabhängig voneinander bestehen, oder teilweise
  aufeinander aufbauen.

  Ein Modul könnte z.B. sein:
  * alles was mit Datenbanken zu tun hat,
  * alle Hilfsfunktionen zur Matrizenrechnung,
  * alles für Finite Elemente, ...

  Man kann sein Programm also senkrecht unterteilen (Datenbanken
  haben nicht mit linearer Algebra zu tun, die beiden kennen sich
  also nicht) oder waagrecht in verschiedene Schichten (Finite
  Elemente benötigen ein Modul zur linearen Algebra, wird aber
  wiederum vom Hauptprogramm benötigt).
  Das Ganze kann man sich schön als Bild von Hierarchien malen
  nach verschiedenen Regeln.

  Die Aufteilung in Module ist natürlich bis zu einem gewissen
  Grad willkürlich, aber je nach Problem gibt es sinnvolle oder
  dämliche Varianten.

  Zu jedem Modul gibt es eine .h, also z.B. eine linearealgebra.h,
  eine fem.h, eine db,h und so weiter.
  Da kommen jeweils Typdefinitonen rein, sowie Deklarationen von
  globalen Daten und Funktionen.
  Diese .h wird dann eingerahmt von:
1
    // Kommentar blabla .. von wem warum weshalb Geschichte...
2
    #ifndef _FEM_H_
3
    #define _FEM_H_
4
    #include <alles>
5
    #include <was>
6
    #include <modul>
7
    #include <so braucht...>
8
    ... alle Typdefinitionen, alle Deklarationen...
9
    #endif // _FEM_H_

- Falls es daneben noch Definitionen gibt, dann packt man diese
  in eine .c gleichen Namens, also linearealgebra.c, fem.c, db.c.

  Die .c #includet am besten auch ihre zugehörige .h.
  Dadurch fallen Abweichungen zwischen Deklaration und Definition
  schnell durch Compilerfehler auf.

Die .c und .h treten also meistens paarweise auf.

>
> Nur, wie mache ich das dann, daß mir all die verschiedenen .c dateien
> jetzt zu einem Programm zusammenkompiliert werden?
>
> Ich sollte vielleicht dazu sagen, daß ich mit Eclipse und GCC unter
> Linux arbeite...

Ich nehme nicht Eclipse, aber da wird es irgendeine Art von 
Projektverwaltung geben, wo man die .c einträgt für jedes Projekt.

von Klaus W. (mfgkw)


Lesenswert?

PS: Bei C++ ist das alles gleich, nur halt *.cpp statt .c.
Außerdem wie bereits oben erwähnt kommen bei C++ alle
Definitionen von inline-Funktionen/Methoden auch indie .h, nicht
in die .cpp.

von hubert (Gast)


Lesenswert?

Das ist jetzt gut verständlich.

Zur Sicherheit: Hab ich das richtig verstanden? Wenn Definitionen zu den 
Deklarationen dazukommen (Funktions- oder bei C++ Klassendefinitionen) 
und ich schreib sie in eine extra .c oder .cpp dann includiere ich das 
.c oder .cpp in den header rein. Muß ich dieses include dann am Ende der 
Headerdatei reinschreiben, so daß sie nach den Definitionen kommt? Oder 
ist das egal?

von Klaus W. (mfgkw)


Lesenswert?

hubert schrieb:
> Das ist jetzt gut verständlich.
>
> Zur Sicherheit: Hab ich das richtig verstanden? Wenn Definitionen zu den
> Deklarationen dazukommen (Funktions- oder bei C++ Klassendefinitionen)
> und ich schreib sie in eine extra .c oder .cpp

Soweit sie halt thematisch zusammenpassen, man muß nicht für jeden 
Pillepallekram eine eigene Datei aufmachen.

> dann includiere ich das
> .c oder .cpp in den header rein.

Nein!!
Was habe ich da angerichtet!

Eine .c oder .cpp wird (fast) nie irgendwo mit #include eingebunden!

Bei einer IDE werden die einzelnen .c und .cpp von der Projektverwaltung
zusammengeschraubt.
Unter der Haube passiert dann das gleiche wie bei manuellem Übersetzen
oder wie bei mir mit make:
Jede .c oder .cpp wird einzeln kompiliert vom Compiler, dabei werden
die jeweils mit #include angegebenen .h eingebunden.
Dabei entsteht aus jeder .c und jeder .cpp je eine Objektdatei
(unter Linux .o, unter Windows .OBJ).
Anschließend wird der Linker angeworfen. Der packt alle .o bzw. .OBJ
und die nötigen Bibliotheken und klebt das alles zu einem
ausführbaren Programm zusammen.

In deinen .c und .cpp stehen nur #includes für die Headerdateien
(.h, bzw. die System-Header bei C++ ohne .h dran, wie bei
#include <iostream>).
Wenn du eine .c oder .cpp mit #include einbindest, hast du
mit 99.9-prozentiger Sicherheit etwas nicht verstanden.


Du schreibst deine .h (siehe oben).
Du schreibst deine .c oder .cpp, darin stehen #include für die .h.
Dann sagst du deinem Eclipse oder wem auch immer, welche
.c kompiliert werden müssen (und damit implizit, welche
Objektdateien später gelinkt werden müssen).
Das wars.

von hubert (Gast)


Lesenswert?

Langsam wird das Bild noch klarer. So wie Du das jetzt beschreibst hab 
ich das in der Ausführlichkeit noch nirgends gelesen. Anscheinend ist 
das ein Thema, das unter ernsthaften Programmierern von Mund zu Ohr 
weitergegeben wird und das kaum einem Lehrbuch mit seinen 
<100-Zeilen-Beispielen wirklich drinsteht oder in den Grundlehrgängen 
geschult wird. Scheint so was wie der Sprung von Lehrgangstheorie zur 
harten Alltagspraxis zu sein.

von Karl H. (kbuchegg)


Lesenswert?

hubert schrieb:
> Langsam wird das Bild noch klarer. So wie Du das jetzt beschreibst hab
> ich das in der Ausführlichkeit noch nirgends gelesen. Anscheinend ist
> das ein Thema, das unter ernsthaften Programmierern von Mund zu Ohr
> weitergegeben wird

wenn du gut aufgepasst hast, dann ist dir vielleicht aufgefallen, dass 
der exakte Meschanismus, wie man seiner IDE mitteilt, welche Einzelteile 
alle zum kompletten Projekt gehören, von der IDE selber abhängt.

Im Extremfall braucht man gar keine IDE

Das Projekt bestehe aus

* main.c      dem Hauptprogramm, welches linear Algebra macht
* linalg.c    da drinnen sind alle Funktionen, die sich um lineare
              Algebra drehen


dann wirft man seine Command line an und

* compiliert main.c einzeln, zb
1
  > cc main.c /OUTPUT=main.o
2
  CC: compiling main.c .... done
3
  0 errors, 0 warnings
4
  >

* compiliert linalg.c einzeln, zb
1
  > cc linalg.c /OUTPUT=linalg.o
2
  CC: compiling linalg.c .... done
3
  0 errors, 0 warnings
4
  >

* linkt die beiden Einzelteile zum kompletten Programm zusammen, zb
1
  > link main.o linalg.o /OUTPUT=main.exe
2
  Linkage Editor V 5.8: linking
3
  * main.o
4
  * linalg.o
5
  * default system library
6
  ->  program created in 'main.exe'
7
  0 errors, 0 warnings
8
  >
und erhält so das fertige Programm main.exe, welches man ausführen kann.

Mit einer IDE (Integrated Development Environment) ist das deutlich 
einfacher: Man sagt der IDE: zu meinem Projekt gehören main.c und 
linalg.c und die IDE kümmert sich darum, dass unter der Haube genau die 
gleichen 3 Schritte ausgeführt werden, wie man sie selbst auch hätte 
händisch machen können. Nur: Wie genau man der IDE mitteilt, was alles 
zum Projekt dazugehört steht im Handbuch der IDE und nicht in einem 
C-Lehrbuch.

von Klaus W. (mfgkw)


Lesenswert?

Beim Kompilieren fehlt (zumindest wenn man den gcc nimmt) jeweils
noch die Option -c, damit nur kompiliert wird und nicht gleich gelinkt,
und die Option, die die Ausgabedatei benennt, ist -o statt /OUTPUT,
zudem wird der gcc auch gleich zum Linken verwendet und die
Ausgabedateien enden üblicherweise nicht auf .exe.
Sonst ist aber fast alles gleich :-)
1
   gcc -c main.c -o main.o
2
   ...
3
   gcc -c linalg.c -o linalg.o
4
   ...
5
   gcc main.o linalg.o -o main

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.