Problem mit Klassendefinitionen (C++ mit Code::Blocks)

Freddycbv

Komplett-PC-Aufrüster(in)
Liebe Community,

Mein Problem ist recht überschaubar, und wahrscheinlich auch leicht zu lösen ^^.
Ich habs in den letzten Stunden jedenfalls nicht geschafft.

Ich habe eine Klasse ClassA mit einem Zeiger auf ein Objekt der Klasse ClassB.
Gleichzeitig habe ich eine Klasse ClassB mit einem Zeiger auf ein Objekt der Klasse ClassA:

Code:
class ClassA
{
    ClassB * ptr;
};

class ClassB
{
    ClassA * ptr;
};
Das Problem ist, das der Compiler die Klasse ClassB noch nicht kennt, wenn es ClassA durchläuft :(

Wie kann ich das bekanntgeben?
 
Zuletzt bearbeitet:
Sag mal bist du Informatik Studierter oder beruflich ?

Ich habe mal privat als Hobby zu coden versucht und bin auch ziemlich weit gekommen wie ich finde.
Leider fand ich keine standard Compiler Umgebung als solide Ausgangsbasis, es durfte auch nichts kosten damals.

Wie weit bist du und was für Compiler etc. benutzt du so kannst mir ein wenig erzählen, denn das (mit 3d grafik usw) coden war wirklich ekstatisch damals ? ^^
 
Ich bin 9.Klässler, und mach alles als Hobby.
Ich arbeite meist mit CodeBlocks, teilweise auch mit Visual c++. Ich bin wirklich kein Pro (sieht man an meinem Problem ^^),
hier im pcgh-extreme forum gibts dagegen einige wirkliche Experten.

Zu meinem Problem: Es kommt mir echt ein wenig crazy vor, da die Problemstellung ja eigentlich häufig vorkommt, und ich bisher nichts machen musste. Mein Compiler streikt einfach, bisher dachte ich nämlich, dass mancher Quellcode vom Compiler doppelt durchgegangen wird.

EDIT: Ich habs jetzt mal in Visual C++ getestet, hier reicht ein einfaches class aus:
Code:
class ClassA 
{     
    class ClassB * ptr; 
};  

class ClassB 
{     
    ClassA * ptr; 
};
Code::Blocks verweigert hier jedoch seinen Dienst mit: "error: field 'ClassB' has incomplete type".
:( Weiss jemand Rat?

EDIT2:
Ich habs jetzt selber hingekriegt, Code::Blocks war Schuld ^^
Ich hab den Zeiger aus ClassA entfernt, und das Projekt erstellt. Dann den Zeiger wieder hinzugefügt, und voila: Es hat funktioniert oO. Natürlich habe ich bei meinen vorherigen Projekten immer alles vorher gecleant(rebuild), doch erst durch dieses in Schrittweise Hinzufügen der Variablen, hats getan. Und selbst jetzt nach ein cleaning oder ein rebuild funktionierts immernoch.
 
Zuletzt bearbeitet:
Jup, das ist die Lösung. :daumen:

Den "Trick", den du verwendet hast, solltest du GANZ schnell wieder vergessen, das wird im Normalfall nicht funktionieren, und das Projekt kann beim nächsten Compilieren schon wieder zicken machen.

die Sache mit VisualStudio ist auch so eine Sache. VS bügelt dir sehr viele Fehler aus, bzw. erlaubt dir eben einige Kniffe/Annehmlichkeiten, die nicht C/C++ konform sind. Das kann man später mal nutzen, aber NICHT!!! so lange man noch lernt, und nicht in einem festen Projekt arbeitet, wo das abgeklärt ist. Das ist einfach verdammt schlechter Stil und den wird man auch nur GANZ schwer wieder los.

Die einzig wirklich korrekte Lösung ist, wie gesagt die Vorwärtsdeklaration.

Das du das nicht kanntest, und auch nicht drauf gekommen bist, ist nicht schlimm. Das ist schon eher ein "fortgeschrittenes" Problem, das es zu lösen gilt. Wir hatten das in der Anfängervorlesung auch erst in der zweiten Semesterhälfte. Vielen war das absolut klar, da Sie schon programmiert haben, aber wer noch nie programmiert hat, der kommt auch darauf nicht.

Auf ein ähnliches Problem wirst du vielleicht bei der Vererbung wieder treffen, oder bei includes ;) Behalt dir das mal im Kopf. Ist wirklich nützlich.

EDIT: seh grad, King hat was anderes geschrieben, als ich gelesen habe.

Das mit class class, ist das wirklich C/C++ konform? Ich glaub nicht, lass mich da aber eines besseren belehren.

Ich würde einfach die Deklaration der Klasse nach vorne schieben, und die Definition in einem zweiten block. So wie man es halt macht.

Btw. mit Header-Files löst sich das Problem eigentlich von selbst, da man dort Deklaration und Definition eben schon in den Files trennt. Da taucht so ein Problem eigentlich nicht auf.

Ich rate dir auch, eigentlich gleich von Anfang an, mit Headerfiles zu arbeiten, das schleift sich dann ein und wird ganz selbstverständlich. Das macht einem das Leben später leichter, wenn man Header-Files verwenden muss/soll
 
class A; ist ganz normaler Standard (funktioniert aber nur falls A dann ein Zeiger ist; in der cpp muss dann aber trotzdem #include <A.h> stehen). Das gibt es übrigens auch schon als Header <iosfwd> für std::out und Konsorten.

Das hat auch eigentlich nur den Zweck, die Compile-Zeit zu drücken.
 
Zuletzt bearbeitet:
Danke für eure Antworten, auch wenn sich mein Problem alleine gelöst hat ^^
Joa einfach vor Class A noch ein Code:
class ClassB;
schreiben :)
Nennt man Vorwärtsdeklaration.
Bringt bei CodeBlocks leider genau den selben Fehler zustande, wenn man zwischen zwei Builds in zwei Klassen jeweils einen Zeiger auf die andere Klasse schreibt. Genauso bei Includes, wenn ich eine ClassA.h und eine ClassB.h habe, die die jeweils andere includieren: Da macht CodeBlocks nicht mit. Wenn man jedoch einen Build dazwischen hat, braucht man sogar gar keine Vorwärtsdeklaration (mach ich jetzt aber natürlich immer ;)). Blöd ist nur der Gedanke, ein neues Projekt in CodeBlocks mit diesen zwei KLassen zu starten :(.

Ich weiss, das ist jetzt offtopic, aber was benutzt ihr eigentlich für eine IDE? Mich würds nämlich ziemlich interressieren, was für gute es sonst noch gibt. Visual C++ ist mir nämlich zu langsam , und CodeBlocks finde ich manchmal schon ein wenig komisch ^^.
 
Sicher, dass du da nix an deinen Projekteinstellungen falsch hast?
Sowas ist mir weder unter Windows noch unter Linux jemals aufgefallen (Compiler natürlich MinGW bzw. gcc)..

Minimalbeispiel?
 
am Anfang am besten einentexteditor und gcc dazu

in den .h Files sollst du ja auch nur schreiben, das es class A bzw B gibt, das die dann aufeinander verlinken, Programmierer du dann erst in der .c Datei. Dann geht das ohne Probleme.
 
Heisst das, das in die Headerdatei ClassA.h nur
reinkommt, und in ClassA.cpp
Code:
#include "ClassB.h"
class ClassA
{
       public:
          ClassA();
          void DoNothing(void){;};
       private:
          ClassB * B;
}
ClassA::ClassA()
{
       B = NULL;
}
Dann wissen die anderen Quelldateien ja garnichts davon, dass ClassA die Funktion DoNothing() bereitstellt. :ugly:
Vll hab ich dich auch falsch verstanden, sorry ^^
 
Also in der Header-Datei, stehen nur die Funktions"köpfe", also die Deklarationen halt. Du knallst da halt alle Funktionen rein, die du verwenden willst, und bei denen du auch willst, dass die jemand kennt. Header-Dateien sind nämlich normal frei zugänglich, wenn überhaupt etwas zugänglich ist.

Die eigentliche Implementierung der Funktionen, Klassen und eben die private Sachen der Klassen etc. stehen dann in der C-Datei. Man führt als in den Dateien die logische Trennung von Deklaration und Definition durch.

Was man natürlich bedenken sollte sind die includes. Auf was man auch aufpassen muss, ist, dass es keinen Zirkelschluss bei den Includes gibt, also Sachen nur einmalig einbinden. C++-Programmierung/ Weitere Grundelemente/ HeaderdateienDa ist das kurz zusammengefasst.

Es geht halt darum, per #ifndef igend_ein_Name #define irgend_ein_Name (aber der gleiche wie bei ifndef!) jetzt kommt dein Code #endif
 
Man kann nicht prinzipiell sagen, dass die Deklaration und Defintion in getrennten Dateien stehen. Es gibt durchaus Fälle, wo es sinnvoll ist, Methoden als inline zu definieren und dann müssen die im Header stehen (sofern die von "externen" Klassen/Funktionen verwendet werden).

Als Beispiel für die Verwendung des class Schlüsselwortes zur Vorwärtsdeklaration nutze ich aber jetzt getrennte Dateien, da es ansonsten eh keinen Sinn machen würde, es zu verwenden :ugly:

Datei: A.h
Code:
// schützt vor mehrfacher Deklaration/Definition der in dieser Header-Datei vorhandenen Methoden, etc.
#ifndef _A_H_INC_
#define _A_H_INC_

class B; // Vorwärtsdeklaration

class A
{
public:
    A();
    ~A();

    void magicFunction();

private:
    B *m_pB;
};

#endif
Datei: A.cpp
Code:
#include "A.h"
#include "B.h" // das ist jetzt hier notwendig

A::A()
{
    m_pB = new B();
}

A::~A()
{
    delete m_pB;
    m_pB = NULL;
}

void A::magicFunction()
{
    m_pB->doNothing();
}
Datei: B.h
Code:
#ifndef _B_H_INC_
#define _B_H_INC_

class B
{
public:
    B();
    ~B();

    void doNothing();

private:
   // ...
};

#endif
Datei: B.cpp
Code:
#include "B.h"

B::B()
{
    // Konstruktor von B
}

B::~B()
{
    // Destruktor von B
}

void B::doNothing()
{
}
 
Zurück