Probleme mit gegenseitigem #include

Hallo zusammen,

ich habe zwei Klassen, die gegenseitig Klassenvariablen der jeweils anderen Sorte haben. Also steht in KlasseA.h drin

#include "KlasseB".h

und umgekehrt.

Jetzt habe ich schon verstanden, daß man diese „Endlosschleife“ abfängt, in dem man folgendes macht:

#ifndef KlasseA\_H
#define KlasseA\_H

#include KlasseB.h
(...Inhalt der Headerdatei...)

#endif

Genauso dann natürlich bei KlasseB.h. Nur klappt das nicht. Ich benutze MS Visual Studio 6.0 und folgende Fehlermeldungen erscheinen, sobald ich das wie oben beschrieben versuche:

KlasseA.cpp
f:\(...)\klasseb.h(15) : error C2146: Syntaxfehler : Fehlendes ';' vor Bezeichner 'kA'
f:\(...)\klasseb.h(15) : error C2501: 'KlasseA' : Fehlende Speicherklasse oder Typbezeichner
f:\(...)\klasseb.h(15) : error C2501: 'kA' : Fehlende Speicherklasse oder Typbezeichner

KlasseB.cpp
f:\(...)\klassea.h(13) : error C2146: Syntaxfehler : Fehlendes ';' vor Bezeichner 'kB'
f:\(...)/klassea.h(13) : error C2501: 'KlasseB' : Fehlende Speicherklasse oder Typbezeichner
f:\(...)\klassea.h(13) : error C2501: 'kB' : Fehlende Speicherklasse oder Typbezeichner

Wobei ‚kA‘ und ‚kB‘ jeweils die Klassenvariablen sind, die folgendermaßen definiert sind (Beispiel KlasseA):

public:
 KlasseB kB;

Kann mir da jemand helfen…?! Ich denke, es ist nicht nötig, den gesamten Source-Code hier zu posten, oder?

Jedenfalls schonmal vielen Dank im Vorraus!

Hendrik.

Kann mir da jemand helfen…?! Ich denke, es ist nicht nötig,
den gesamten Source-Code hier zu posten, oder?

Von den beiden Header Dateien wäre dies nicht schlecht… dann kann man leichter sehen was falsch ist… mit gegenseitigem Include hat das denke ich nichts zu tun.

Grüße
Bruno

Hi Bruno,
danke für deine schnelle Antwort. Ich habe die Header-Dateien nur leider jetzt gerade nicht hier (bin jetzt woanders als vorhin). :frowning:

Nur soviel weiß ich noch: Wenn ich die Reihenfolge in der Header-Datei folgendermaßen ändere

#include KlasseB.h
#ifndef KlasseA\_H
#define KlasseA\_H
(...Inhalt der Headerdatei...)
#endif

sind alle Fehlermeldungen verschwunden und ich bekomme dafür eine Art Heap-Overflow Fehler (logisch, wegen Endlosschleifenproblematik)
Nagut, ich werde am Montag mal noch meine Header-Dateien hier posten, danke soweit und schönes Wochenende!

Hendrik.

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Hallo Hendrik!

Du mußt den Header hinter der geschweiften Klammer mit einem Semikolon abschließen.

#ifndef
#define
{
Header
};
#endif

Gruß

Michael

Hallo Hendrik,

Hier hast du den Fehler gemacht:

Datei „Klasse A.h“ :

#ifndef Klasse **B** \_H
#include "Klasse **B**.h"
#endif

#ifndef Klasse **A** \_H
#define Klasse **A** \_H

(...Inhalt der Headerdatei Kalsse **A**...)

#endif

Datei „Klasse B.h“ :

#ifndef Klasse **A** \_H
#include "Klasse **A**.h"
#endif

#ifndef Klasse **B** \_H
#define Klasse **B** \_H


(...Inhalt der Headerdatei Kalsse **B**...)

#endif

MfG Peter(TOO)

ich habe zwei Klassen, die gegenseitig Klassenvariablen der

Klassen, die gegenseitig aufeinander Bezug nehmen, werden üblicherweise als Designfehler angesehen. Versuche Dein Klassenmodell so umzubauen, dass sich Klassen nicht gegenseitig benötigen. Damit vermeidest Du einmal das Problem der endlosen Includes und das Klassendesign wird auch sauberer.

Gruß
Marian

Hallo nochmal,
schonmal vielen Dank für die Tips! Das fehlende Semikolon war’s leider nicht und auch der Tipp von Peter hat nicht so wirklich geholfen: Dann kam wieder der Heap-Überlauf-Krempel.

Jedenfalls sind hier noch die Header-Dateien, die die im original Posting beschriebenen Probleme erzeugen. Hoffentlich hilft das weiter… :-/

Hendrik.

P.S.: Die Defines haben die von Visual C++ generierten Schlüssel, aber das ist ja egal.

//////////////////////////////////////////////////////////////////////
//
// KlasseA.h: Schnittstelle für die Klasse KlasseA.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX\_KLASSEA\_H\_\_97CF91F6\_6ACC\_45A6\_BAD4\_75CCD95C471A\_\_INCLUDED\_)
#define AFX\_KLASSEA\_H\_\_97CF91F6\_6ACC\_45A6\_BAD4\_75CCD95C471A\_\_INCLUDED\_

#include "KlasseB.h" // Hinzugefügt von der Klassenansicht

class KlasseA 
{
public:
 KlasseB kB;
 KlasseA();
 virtual ~KlasseA();

};

#endif // !defined(AFX\_KLASSEA\_H\_\_97CF91F6\_6ACC\_45A6\_BAD4\_75CCD95C471A\_\_INCLUDED\_)


//////////////////////////////////////////////////////////////////////
//
// KlasseB.h: Schnittstelle für die Klasse KlasseB.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX\_KLASSEB\_H\_\_8F0A3391\_8BD2\_4D63\_8F2E\_8D0A6E6F805C\_\_INCLUDED\_)
#define AFX\_KLASSEB\_H\_\_8F0A3391\_8BD2\_4D63\_8F2E\_8D0A6E6F805C\_\_INCLUDED\_

#include "KlasseA.h" // Hinzugefügt von der Klassenansicht


class KlasseB 
{
public:
 KlasseA kA;
 KlasseB();
 virtual ~KlasseB();

};

#endif // !defined(AFX\_KLASSEB\_H\_\_8F0A3391\_8BD2\_4D63\_8F2E\_8D0A6E6F805C\_\_INCLUDED\_)

Hallo Marian,

mich würde interessieren, was man in meinem konkreten Fall da tun könnte. Ich modelliere einen aus Knoten und Kanten bestehenden Graphen. Aufgrund des Algorithmus, der später diese Datenstruktur verwendet, ist es notwendig, daß sowohl jeder Knoten seine benachbarten Kanten kennt, als auch daß jede Kante ihre beiden Knoten kennt. Wie soll ich das auflösen? Durch eine dritte Klasse, die jeweils die passenden Knoten/Kanten raussucht? Das wäre viel zu langsam denke ich. Der Graph wird aus mehreren Tausend Knoten und vielleicht bis zu 100000 Kanten bestehen und es wird millionenfach notwendig sein, passende Knoten/Kanten herauszusuchen.

Oder gibt es da noch andere Möglichkeiten, das zu modellieren…?

Viele Grüße,

Hendrik.

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Hallo Hendrick,

Du machst ja auch immer noch den gleichen Fehler !!!
Du darfst den #include nur ausführen wenn die entsprechenden definitionen noch nicht geladen wurden !!!

P.S.: Die Defines haben die von Visual C++ generierten
Schlüssel, aber das ist ja egal.

//////////////////////////////////////////////////////////////////////
//
// KlasseA.h: Schnittstelle für die Klasse KlasseA.
//
//////////////////////////////////////////////////////////////////////

#if
!defined(AFX_KLASSEA_H__97CF91F6_6ACC_45A6_BAD4_75CCD95C471A__INCLUDED_)
#define
AFX_KLASSEA_H__97CF91F6_6ACC_45A6_BAD4_75CCD95C471A__INCLUDED_

#if !defined AFX_KLASSEB_H__8F0A3391_8BD2_4D63_8F2E_8D0A6E6F805C__INCLUDED_

#include „KlasseB.h“ // Hinzugefügt von der Klassenansicht

#endif

class KlasseA
{
public:
KlasseB kB;
KlasseA();
virtual ~KlasseA();

};

#endif //
!defined(AFX_KLASSEA_H__97CF91F6_6ACC_45A6_BAD4_75CCD95C471A__INCLUDED_)

//////////////////////////////////////////////////////////////////////
//
// KlasseB.h: Schnittstelle für die Klasse KlasseB.
//
//////////////////////////////////////////////////////////////////////

#if
!defined(AFX_KLASSEB_H__8F0A3391_8BD2_4D63_8F2E_8D0A6E6F805C__INCLUDED_)
#define
AFX_KLASSEB_H__8F0A3391_8BD2_4D63_8F2E_8D0A6E6F805C__INCLUDED_

#if !defined AFX_KLASSEA_H__97CF91F6_6ACC_45A6_BAD4_75CCD95C471A__INCLUDED_

#include „KlasseA.h“ // Hinzugefügt von der Klassenansicht

#endif

class KlasseB
{
public:
KlasseA kA;
KlasseB();
virtual ~KlasseB();

};

#endif //
!defined(AFX_KLASSEB_H__8F0A3391_8BD2_4D63_8F2E_8D0A6E6F805C__INCLUDED_)

Hallo Hendrik,

Es gibt 2 Dinge zu beachten:

  1. Du machst einen Fehler bei den Deklarationen der beiden Klassen: man kann nicht eine Klasse A deklarieren die als Aggregat (also als member-variable) eine Variable vom Typ B aufnimmt, wenn gleichzeitg B eine Member-Variable vom Typ A hat. Warum nicht? Weil der Compiler dann die Größe der Objekte nicht bestimmen kann: beim Kompilieren der klasse A muss der Compiler die Größe der Member-Variablen B wissen. Die Größe von B ist aber ist aber abhängig von der Größe von A, da ja B eine Member-Variable vom Typ A hat. Das geht also nicht.

  2. Du kannst allerdings in einer der beiden Klassen (sagen wir B) einen Pointer oder eine Referenz auf ein Objeckt der anderen Klasse (also vom Typ A) aufnehmen. Das ist ein durchaus gängiges Design, und manchmal unabwendbar. In diesem Fall sollte man dann mit sog. Foward-Deklarationen arbeiten. Z.B.:

    // A.h: Deklaration von class A
    // *****************************
    #ifndef A_H
    #define A_H

    #include „B.h“

    class A
    {
    // Deklarationen
    B m_b; // member-var. vom typ B
    };

    #endif // ndef A_H

    // B.h: Deklaration von class B
    // *****************************
    #ifndef B_H
    #define B_H

    // foward declaration of A
    class A;

    class B
    {
    // Deklarationen
    A* m_pA; // member-var. vom typ A* (pointer auf A)
    };

    #endif

In der Implementierungs-Datei von B also B.cpp musst Du dann noch

#include "A.h"

einfügen, da Du ja mit Sicherheit irgendwas mit dem pointer m_pA machen wirst, z.B. eine Methode von A aufrufen. Dazu muss der Compiler natürlich wissen, dass es die Methode gibt.

Aber wichtig zum Verständnis ist: dem Compiler reicht die foward-Deklaration der Klasse A in der header-Datei von B, da er die Größe der Member-Variablen B::m_pA auch ohne die Deklaration von A bestimmen kann, denn eine Pointer hat ja immer die gleiche Größe (i.d.R.4Byte). Versuchst Du das gleiche in der Header-Datei von A (also lediglich eine foward-Deklaration von B anstatt B.h zu includen), gibt es wieder Mecker vom Compiler.

Mittels der Foward-Deklarationen ist es sogar möglich auf die sog. define-Wächer zu verzichten, kann ich aber nicht empfehlen.

Gruss Rolf

Hi Rolf,

erstmal noch vielen Dank für deine Antwort und entschuldige bitte die späte Antwort von mir. Ich habe jetzt mal ausprobiert, was du mir geschrieben hast und… es funktioniert! :smile: Der Knackpunkt war tatsächlich die Forward-Deklaration. Also: Alles bestens jetzt!

Viele Grüße und auch nochmals Danke an die anderen Antworter,

Hendrik.

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]