[C++] Klassen aufeinander verlinken

i_hasser

Grand Admiral Special
Mitglied seit
06.06.2002
Beiträge
18.964
Renomée
85
Standort
IO 0x60
Hi

Und wieder ein Problem :P

Ich will sowas machen

Code:
class a
{
    public:
    void fb(b* ptr);
    void fc(c* ptr);   
};

class b
{
    public:
    void fa(a* ptr);
    void fc(c* ptr);   
};

class c
{
    public:
    void fa(a* ptr);
    void fb(b* ptr);   
};

Die 3 Klassen sollen letztendlich aufeinander linken.
Dummerweise haut mir der gcc haufenweise nichtssagende Fehlermeldungen entgegen. Die 1. ist jeweils bei "f[x]([x]* ptr);" und lautet "[x] not declared in this scope".
Die Klassen befinden sich alle jeweils in separaten .cpp und .h.
 
Ich weis jetzt nicht ob das irgend einem Standard entspricht, aber man kann anscheinend auch für Klassenheader Header (besser: Prototypen) schreiben (ich weis, klingt *chatt*).

Damit funktioniert das:

Code:
class a;
class b;
class c;

class a
{
    public:
    void fb(b* ptr);
    void fc(c* ptr);   
};

class b
{
    public:
    void fa(a* ptr);
    void fc(c* ptr);   
};

class c
{
    public:
    void fa(a* ptr);
    void fb(b* ptr);   
};
 
Das ist der übliche Stil.
Die modernsten Compiler machen das Gerüchten zufolge selbst, d.h. du kannst dir die ersten drei Zeilen sparen (die "Deklaration"). Habe ich aber noch nie gesehen...

exr
 
Na das ist es doch gerade, wenn ich die 1. 3 Zeilen weglasse wirft mir der gcc haufenweise Fehlermelungen um die Ohren. Auch wenn ich 2 Header aufeinander include.
 
Eben. Ging mir auch immer so. Daher wirst du im Moment nicht drumrumkommen. Habe auch noch keinen Compiler gesehen der das alleine rausfindet. Solls aber geben... ich werd mal fragen welcher das sein soll.

exr
 
ist bei c auch nix anderen gewesen wenn das jemand kennt, da hat man die prototypen der fkten auch über main geschrieben, und die richtigen dann drunter..

grund ist es wenn der compiler an die stelle kommt muss er die fkt/klassen schon kennen, und eine deklaration reicht da
 
Die Funktionsprototypen gehören in den Header, nicht über main ;)

Das komische ist ja, dass es noch etwas komplizierter ist:

a.h
Code:
#include <b.h>

class a
{
   public:  
       fb (b* ptr);
};

b.h
Code:
#include <a.h>

class b
{
   public:  
       fa (a* ptr);
};


So sieht es mit headern aus, bevor in a.h fb auftaucht sollte er eigentlich schon per Include über "class b..." gestollpert sein.
 
Wozu das Ganze in unterschiedlichen Headern? Die Klassen nehmen doch eh schon jeweils Bezug zu den anderen, brauchen also alle Prototypen-Definitionen. Pack doch alles in abc.h, wie Du weiter oben schon angegeben hast...
 
Das werden ziemlich riesige Klassen ;). Das Programm wird hauptsächlich aus diesen 3 Klassen bestehen, bzw. wird es 3 Klassen geben die je eine der Klassen oben implementieren und die bilden das Program an sich.

Außerdem packt KDevelop jede Klasse in einen eigenen Header. Ich habs jetzt so gelößt:

abc.h
Code:
#ifndef ABC_H
#define ABC_H
class a;
class b;
#endif

Und a.h bzw. b.h includen abc.h
 
Um einen Header nur 1x zu includen, gibt's "#pragma once". Weiß aber nicht, ob das was MS-spezifisches ist.
 
Original geschrieben von intel_hasser
Hi

Und wieder ein Problem :P

Ich will sowas machen

Code:
class a
{
    public:
    void fb(b* ptr);
    void fc(c* ptr);   
};

class b
{
    public:
    void fa(a* ptr);
    void fc(c* ptr);   
};

class c
{
    public:
    void fa(a* ptr);
    void fb(b* ptr);   
};

Die 3 Klassen sollen letztendlich aufeinander linken.
Dummerweise haut mir der gcc haufenweise nichtssagende Fehlermeldungen entgegen. Die 1. ist jeweils bei "f[x]([x]* ptr);" und lautet "[x] not declared in this scope".
Die Klassen befinden sich alle jeweils in separaten .cpp und .h.

Ohne den entsprechenden Code ist es reichlich schwer hier zu helfen. Der Fehler kann da an so ziemlich jeder Stelle sein.
 
Original geschrieben von TiKu
Um einen Header nur 1x zu includen, gibt's "#pragma once". Weiß aber nicht, ob das was MS-spezifisches ist.

Ist es - das #ifndef ... ist bei gcc standard.

@Puck

Kopier den Code einfach so, ohne die Funktion selbst in einen Header, mach die Funktionen von mir aus alle virtual und versuch das zu kompilieren - nur den Header. Gcc wird dich mit Fehlermeldungen zutexten, da brauchts keine Implementierung von den Funktionen.

Ich programmiere nicht das erste mal was in C++...

Also erst denken, dann posten ;)
 
Original geschrieben von intel_hasser
Kopier den Code einfach so, ohne die Funktion selbst in einen Header, mach die Funktionen von mir aus alle virtual und versuch das zu kompilieren - nur den Header. Gcc wird dich mit Fehlermeldungen zutexten, da brauchts keine Implementierung von den Funktionen.

Ich programmiere nicht das erste mal was in C++...

Also erst denken, dann posten ;)

Ich bin gerade dabei das zu probieren, nur ist das bei leibe kein c&p, so wie du es darstellst.
 
Doch, ist es. Mach mal sowas hier:


main.c
Code:
#include <aux.h>

int main()
{
    return 0;
};


aux.h
Code:
class a
{
    public:
    void fb(b* ptr);
    void fc(c* ptr);   
};

class b
{
    public:
    void fa(a* ptr);
    void fc(c* ptr);   
};

class c
{
    public:
    void fa(a* ptr);
    void fb(b* ptr);   
};


Und du wirst genau das Problem bekommen. Oder du machst es so wie ich über Header (jede Klasse in einen eigenen Header, die Klassen includen sich gegenseitig - das macht ja die Prototypen eigentlich überflüssig) und du wirst auch dieses Problem haben.
 
Ist doch auch logisch, die Klassen sind ja zum Parse-Zeitpunkt nicht bekannt. Genauso bei mehreren Headern, da hast du rekursive includes. Da fehlen dann die Deklarationen.
 
Aber wenn ich das über mehere Headers mache, zb. so:

a.h
Code:
// ifndef krempel damit nur 1mal included

#include <b.h>
class a
{
   public:
   fb (b* ptr);
};
#endif

b.h
Code:
//ifndef Krempel

#include <a.h>
class b
{
   public:
   fa (a* ptr);
};
#endif

und der Compiler anfängt die a.h zu parsen stolpert er erstmal über das Include und fängt an die b.h zu lesen. Da stolpert er über #include <a.h>, die nimmt er aber net. Dann gehts weiter zu class b -> ergo dürfte der Compiler mitbekommen, dass es nun eine neue Klasse b gibt.
Die Klasse b geht dann ohne weiteres tamtam zuende. Ok, da gibts ein Problem, in b kennt er für fa die Klasse a noch nicht, weil er die Klasse a noch nicht komplett geparst hat (weil ja include b.h), aber das define schon ausschließt, dass b nochmal a included. Also müsste man das #define theoretisch hinter class a bzw. class b setzen (mitten in die Klasse rein) - dann würde es wohl funktionieren, wäre aber ein bissel unsauber.

Die Klassenstruktur ist ziemlich komplex (aber nötig) und desswegen hab ich hier so viel weggelassen. So siehts momentan aus:

Code:
class Sub_Helper
{
  class Sub_Config
  {
    class ConfigOpt
    {
      enum ArgType;
    }
   
    class ConfigArg;
  }
  class Sub_Comm;
}

class Sub_Base : Sub_Helper::Sub_Config;

class Sub_CPU : Sub_Base;
class Sub_Mem : Sub_Base;
class Sub_Per : Sub_Base;

Die Funktionsprototypen hab ich jetzt alle weggelassen, das wird sonst zu unübersichtlich.

Hätte ich das alles gepostet, hätte bestimmt keiner Lust gehabt sich da durchzufriemeln ;)
 
Bah, hör auf Klassen in Klassen zu definieren. Dazu gibt es Mehrfachdeklarationen (also so, wie du es zuerst gemacht hast).
 
Du meinst sowas wie

Code:
class a
{
    class b;
}

class a::b
{
...
}

???

Mir persönlich gefallen Klassen in Klassen, daher nehm ich sowas auch ungehemmt ;).
In der Strukturellen Darstellung würde ich gegenüber

Code:
class a
{
   class b
   {
     .....
   }
}

nichts ändern.


PS Das oben ist natürlich nur der momentane Status, wenn die Geschichte steht wirds da noch viel mehr Klassen in Klassen geben.
 
Original geschrieben von intel_hasser
Du meinst sowas wie

Code:
class a
{
    class b;
}

class a::b
{
...
}

???


Nein, das wäre ja abgeleitet. Alles was über trivialen Code hinausgeht, verpackt man in separate Dateien, und Klassen gehen definitiv über Trivialität hinaus (sonst bräuchte man sie ja nicht). Das gibt dem Ganzen erst mal Struktur. Also Klassendefinitionen in Headern, schön strukturell getrennt.

Nebenbei gefragt, das wird nicht gerade dein OS?

EDIT: Nein nichtmal abgeleitet, den Stuß kenne ich noch gar nicht. ???
 
Den "Stuss" (nach neuer Rechtschreibung mit ss ;)) hab ich mir auch eben gerade ausgedacht, so hätte ich das rein intuitiv probiert.

Aber nein, das wird nicht mein OS. Aber was in die Richtung. Die Klassen geben ja nur die Struktur vor, und die Struktur bleibt erhalten, auch wenn ich den Krempel meinentwegen in extra Dateien auslagere.
 
So, also mein C++ Instinkt hat mich nicht getäuscht, es geht tatsächlich auch so. Die Klasse wird eben wie eine Funktion außerhalb vom eigentlichen Klassenheader "implementiert".
 
Ja, war ich dann auch drauf gekommen, dass :: der Bereichsoperator ist. Nur sehe ich den Sinn darin nicht, einen Datentyp nur innerhalb eines Datentyps zu definieren.
 
Namespace sauber halten, Zugehörtigkeiten ausdrücken, Prioritäten ausdrücken, Präfixe sparen...

Such dir was aus ;)


Mir ist wohler wenn ich sehe, dass der Namespace nur eine handvoll Klassen enthält. Wirkt nicht so überladen und undurchsichtig.
Das Sub_Helper hab ich wirklich nur, um das was es enthält vom eigentlichen Namespace fernzuhalten, da sollen nur 4 Klassen rein, die da auch was zu suchen haben.
 
Dafür gibt es explizit das Schlüsselwort namespace. Bei Variablen sehe ich das ja ein, aber ganze Datentypen auf nur eine Bereich beschränken. *noahnung*
 
Wenn du sie woanders definitiv nicht brauchst - warum nicht?

Außerdem, mit Sub_Helper::Sub_Config kann ich immernoch von überall (auch anderen Namespaces, das Zeug liegt in cse_core, also insgesammt mit cse_core::Sub_Helper::Sub_Config) auf die Klasse zugreifen, da public.

Namespaces sind auch nur ziemlich eingeschränkte Klassen ;)
 
Zurück
Oben Unten