[C++] Probleme mit gegenseitigen Includes

The_Edge

Grünschnabel
Hallo zusammen!

Ich arbeite mich jetzt seit ein paar Wochen in C++ ein. Habe bis jetzt jedes Problem mir ergoogeln können, aber hier komme ich nicht weiter:

Ich habe ein paar Klassen geschrieben, die ich mit Pointern aufeinandern ausstatten wollte. Nun hatte ich mich schon einmal mit Includes auseinandergesetzt und verwende seitdem Include-Guards nach folgenden Schema:
---------------------------------------------------
#ifndef __A
#define __A

#ifndef __B
#include __B
#endif

#ifndef __C
#include __C
#endif
...

#include<vector>
#include...

class A{
...
}

#endif //ifndef __A
---------------------------------------------------
In der cpp-Datei machen ich dann nur noch einen include auf die entsprechende Headerdatei und ein Mapping der Alloc()-Funktion auf die Debug-Version, von wegen Memory-Leaks und so.

Das ging einige Zeit so gut, bis irgendwann sehr merkwürdige Fehler auftraten; Manche Dateien konnte ich über eine andere Datei kompilieren, aber nicht von sich aus. Die Kompilerfehler treten plötzlich massiv auf. Der Häufigste ist " Syntaxfehler: Es fehlt ';' vor ..." ...irgendeiner Klammer.

Ich habe rumprobiert und über einen Include-Graphen herausgefunden, dass diese Fehler auftreten, wenn ein Zyklus vorliegt. Vielleicht gäbe es einen Weg, dieses gegenseitige Abhängigkeitsproblem über ein Nichtzyklischen Graphen so lösen, aber das kann es ja wohl nicht sein.

Mache ich da irgendwas falsch bei den Include-Guards?

Ach ja meine Umgebung (Aber daran wird wohl nicht liegen):
WindowsXP
MS Visual C++ .NET

Gruss
 
Wie wärs einfach mal, wenn du ein ; hinter die Klassendeklaration setzt, hab gehört das man das so macht, und das schon vor einigen Jahren ;)

Also

class A
{
....
};


Im überigens könntest du mal schreiben in welcher Datei was ist, also ich will dir das mit den Includes mal eben an einem 2 Dateien Beispiel erklären :

DATEI A beinhaltet :

#include "dateib.h"

class A
{

};



DATEI B beinhaltet :

#include "dateia.h"

class B
{

};



Würden wir jetzt KEIN indef machen, würden sich die beiden Dateien immer wieder gegenseitig includen, der Compiler würde als in eine Endlosschleife geraten.
Um das zu verhindern setzt mal ein

#ifndef A
#define A

hier den inhalt von DATEI A

#endif

und für Datei B das äquivalente dazu ein. Somit wird ein Flag gesetzt, das die Datei bereits vom Compiler gelesen wurde, und dann nicht noch ein weiteres mal compiliert.

ifndef bedeutet IF NOT DEFINE



Hoffe das war deutlich und hat deine Frage beantwortet, wenn nicht, dann meld dich nochmal...
 
Das mit den fehlenden Semikolon nach der Klassendeklaration war ein Tippfehler. Ich denke, ich habe das Problem selber lösen können. Es lag an den Pointern. Trotzdem vielen Dank an alle. Um das Problem auf die minimalste zu reduzieren hier zwei Beispielklassen:
Code:
#ifndef __A
#define __A

#ifndef __B
#include "B.h"
#endif

class A{
private:
	B* bPointer;
};
#endif
und entsprechend...
Code:
#ifndef __B
#define __B

#ifndef __A
#include "A.h"
#endif

class B{
private:
	A *aPointer;
};

#endif

Es gibt hier ein Problem, da wegen der Include-Guards die B-Klasse nicht definiert wird. Hierzu müsste diese ja A.h includieren, was wegen der Includeguards nicht ausgeführt wird. Es muss also entsprechend eine Klasse zuerst definiert werden, was wegen der Pointer nicht funktionieren wird. Die Lösung für dieses Problem ist eine Forward-Deklaration. Die Klasse A wird sozusagen zunächst ohne Inhalt deklariert. Die Klasse B kann dann deklariert werden, da ein Pointer immer gleich groß ist. Ist Klasse B deklariert, so kann dann auch Klasse A deklariert werden. B.h muss so aussehen:

Code:
#ifndef __B
#define __B

#ifndef __A
#include "A.h"
#endif

class A;

class B{
private:
	A *aPointer;
};
#endif

Das entscheidene ist "class A;". Es wird nur die Klasse deklariert, jedoch nicht die Methoden. Die Header-Dateien lassen sich so nun kompilieren.
Ein Problem trat jedoch auf, als ich eine Methode aus der Klasse A in B.cpp verwenden wollte. Dies kam daher, dass die Methoden der Klasse A für B gar nicht nach deklariert wurden. Hier musste dann noch ein einfaches #include "A.h" in die cpp-Datei geschrieben werden.

Ich wollte eigentlich alle benötigten Includes in die Header-Dateien schrieben. Scheinbar ist dies genau der falsche Weg. Also eher nur die benötigten Includes für die Deklaration in die Header-Datei. Aber darüber bin ich mir noch nicht so sicher.

Gruss
 
Hy!

Im Header in dem die Klasse "B" definiert wird, kannst du übriegens den Include-Schutz für A weglasse, da A.h sich sowieso gegen mehrfachen Include selbst schützt.

mfg
uhu01
 
@The_Edge

Genau das habe ich in dem Beispiel von mir geschrieben... im überigens, an den Pointern lag das bestimmt nicht... das war höchstens ein weiterer Fehler. Du solltest dir die von mir oben beschriebene Art des Doppelinclude Schutzes aneigenen, das macht man eigendlich überall so.

Und Uhu hat vollkommen recht, doppelt schützen hilft nicht besser, ich habe das nur bei mir so gemacht weil man ja auch mehr als nur 2 Header haben kann, daher ist das schon besser wenn man das jeder Header spendiert...
 
Diese "externen" (ich hoffe das ist jetzt der richtige Begriff) Include-Guards hatte ich bereits verwendet. Vielleicht war das nicht aus meinem ersten Beipiel deutlich geworden. Dort habe ich bereits das ganze gemantelt durch:

#ifndef __A
#define __A
...
#endif //ifndef __A

Mit dieser Art von Fehlern habe ich mich schon vor ein paar Wochen rumgeschlagen. Da waren die Fehlermeldung bei weitem nicht so komisch wie bei diesem Problem. Es wurde sogar das Problem sehr eindeutig als "already defined" u.a. vom Kompiler ausgegeben. Im Gegensatz dazu, gab es bei diesem Problem hunderte Meldungen wie "; fehlt vor {".
Eine weitere Sache, warum die mehrfachen Include wohl nicht verantwortlich sind, ist, dass in einigen Fällen sich zwei Dateien zwar "in eine Richtung", aber nicht in die andere Richtung kompilieren ließen. Beide Dateien hatten einen gegenseitigen Include. Logischerweise würde das Problem auftauchen, egal, welche Datei zuerst kompiliert wird.

Gruss
 
Dann poste doch mal den Quellcode der Dateien, oder hänge diese mal diesem Thread an, dann kann man da mal schaun... also wenn da steht das ein Semikolon fehlt, dann fehlt dort auch meistens eins ;)
 
Zurück