Vererbung
-
Hallo,
ich brauche zum ersten mal Vererbung in C++ und stoße auf Hindernisse in Form von einem Compiler-Fehler.
Der Fehler:
expected class-name before '{' token
Wall.h (soll von Block.h erben)
#ifndef WALL_H_ #define WALL_H_ #include "Block.h" // <-- class Block reinholen #include "Engine.h" // <-- unwichtig class Engine; class Wall : public Block { // <-- hier Fehler protected: Engine* engine; public: SDL_Rect box; Wall(Engine* enginee, int x, int y, int w, int h); void show(); }; #endif
Block.h
#ifndef BLOCK_H_ #define BLOCK_H_ #include "Engine.h" class Engine; class Block { protected: Engine* engine; public: SDL_Rect box; Block(Engine* enginee, int x, int y, int w, int h); void show(); }; #endif
bisher sehen Wall und Block ziemlich identisch aus, das ist aber einfach weil ich bisher nur Wall hatte und jetzt versuche Block neu zu erstellen um Vererbung einzuführen, weil ich noch mehr Elemente wie Wall brauche, die von Block erben sollen.
Wie dem auch sei, warum sagt der mir so einen Fehler an? Kennt er "Block" nicht als class? Er hat doch den include?
-
Das, was man hier sieht sieht eigentlich gut aus (syntaktisch auf jeden Fall; viel Sinn macht die Vererbung so nicht nicht, aber ich denke, dass dir das bewusst ist ;)).
Kannst du das Beispiel auf ein sonst unabhängig kompilierbares reduzieren?
Ich würde sagen, dass genau "Engine.h" das Problem macht. Dort hast du wahrscheinlich "Wall.h" und/oder "Block.h" inkludiert.
Falls ja (oder auch sonst) lies mal das hier durch.
-
Lass mich raten: Engine.h inkludiert Wall.h -> BAM! zirkulärer Include.
-
Den Fehler kann ich aus diesem Code auch nicht erkennen, womöglich ist doch in der "Engine.h" etwas kaputt.
Allerdings solltest du die Vererbung etwas gründlicher erledigen anstatt nur den Code zu duplizieren:
- Wall benötigt keine eigene Engine und Box, da es diese Elemente von Block übernimmt
- die show()-Methode soll vermutlich virtuell werden
- und öffentliche Member wie box sind zumindest eine ungeschickte Lösung (unabhängig von Vererbung)PS: Und die Forward-Deklaration von Engine ist auch unnötig, wenn du sowieso vorher die komplette Definition der Klasse eingebunden hast.
-
Ja, die Engine.h includiert Wall, aber bisher hat es ja auch funktioniert.
Und "class Wall;" ist schon oben in der Engine.h deklariert, um so eine zirkulation zu vermeiden, was bisher auch eigentlich funktioniert hat (hatte früher schonmal probleme mit zirkulation, daher die deklaration). Erst seit ich den Vererbungsversuch mache, geht das nicht mehr.
Habe der Engine.h auch mal "class Block;" hinzugefügt, das behebt aber gar nichts. Weiterhin der identische Fehler
Wenn ich "class Block;" in Wall.h deklariere, kommen übrigens zwei andere Fehler statt dem bisherigen:
forward declaration of 'struct Block'
invalid use of incomplete type 'struct Block'
Um die Fehlerpositionen zu zeigen nochmal kurz die Wall.h:
#ifndef WALL_H_ #define WALL_H_ #include "Block.h" #include "Engine.h" class Block; // <-- hier erste Fehlermeldung class Engine; class Wall : public Block { // <-- hier zweite Fehlermeldung protected: Engine* engine; public: SDL_Rect box; Wall(Engine* enginee, int x, int y, int w, int h); void show(); }; #endif
-
Dein Problem besteht darin, daß sich diese Header erstens (direkt oder indirekt) gegenseitig einbinden und zweitens per Include-Guards gegen Mehrfach-Definitionen geschützt sind. Dadurch stehen die Definitionen im fertigen Programm vermutlich nicht in der Reihenfolge, die du benötigst.
Die Lösung ist (vermutlich) recht einfach: Wall und Block benötigen keine Definition der Engine, um definiert zu werden, also reicht dort die Forward-Deklaration (ohne den Include). Ob die Engine-Klasse von der Definition von Block oder Wall abhängig ist, kann ich nicht beurteilen - vermutlich ist sie es nicht.
-
Djinndrache schrieb:
Ja, die Engine.h includiert Wall, aber bisher hat es ja auch funktioniert.
Dann hattest du bisher Glück.
Djinndrache schrieb:
Und "class Wall;" ist schon oben in der Engine.h deklariert, um so eine zirkulation zu vermeiden [...]
Der einzige Weg um ein zirkuläres Include zu vermeiden ist kein zirkuläres Include zu machen. Eine Forward-Declaration allein hilft da absolut gar nix.
-
Dann versuch ich wohl mal includes auszumisten, wenn sie nicht unbedingt benötigt werden.
Wenn ich die include Engine.h rausschmeiße, gibts aber schon Fehler:
forward declaration of 'struct Engine'
in der Zeile "class Engine;" von Block.h
und zweimal der Fehler
invalid use of incomplete type 'struct Engine'
in der Block.cpp auf folgenden Zeilen:
void Block::show() { SDL_FillRect(engine->screen, &box, SDL_MapRGB(engine->screen->format, 0x00, 0x00, 0x00)); }
Macht ja auch Sinn der Fehler, er weiß nicht was engine->screen ist oder ob es das überhaupt gibt. Also brauch ich den include der Engine.h in Block.h oder nicht?
(Ich hab im moment viele public variablen, das werde ich später noch geschickter durch getter und setter Methoden bauen, vorerst ist das aber ok so)
-
Das erste klingt nicht nach einer Fehlermeldung - jedenfalls nicht nach einer vollständigen.
Djinndrache schrieb:
Macht ja auch Sinn der Fehler, er weiß nicht was engine->screen ist oder ob es das überhaupt gibt. Also brauch ich den include der Engine.h in Block.h oder nicht?
In der Block.h benötigst du den Include nicht (dort reicht die Forward-Deklaration), in der Block.cpp schon.
-
Du brauchst weder in Block.h noch in Wall.h Engine.h inkludieren. Dort reicht eine forward-declaration, so wie du sie schon in Zeile 6 bzw 7 hast.
Allerdings musst du Engine.h in Block.cpp und Wall.cpp inkludieren.
Ich weiss nicht wie es dein compiler handhabt (VS2010 hat keine Probleme damit), aber es empfiehlt sich struct und class nicht zu mischen. Sprich du solltest sowohl bei der Deklaration als auch bei der Definition entweder struct oder eben class verwenden (nicht mal so mal so).
Wie gesagt, ich weiss nicht inwiefern andere compiler damit Probleme haben und ob es grundsätzlich Probleme geben könnte, aber ich würd rein aus Konsistenzgründen schon dazu tendieren, nicht zu mixen.
-
CStoll schrieb:
Das erste klingt nicht nach einer Fehlermeldung - jedenfalls nicht nach einer vollständigen.
Djinndrache schrieb:
Macht ja auch Sinn der Fehler, er weiß nicht was engine->screen ist oder ob es das überhaupt gibt. Also brauch ich den include der Engine.h in Block.h oder nicht?
In der Block.h benötigst du den Include nicht (dort reicht die Forward-Deklaration), in der Block.cpp schon.
Ah, natürlich! Hab es jetzt funktionsfähig bekommen
Die Fehlermeldung war so vollständig, zumindest laut eclipse.
Ich werde jedenfalls erstmal kräftig den Code aufräumen bevor ich was neues mache, da es mittlerweile doch schon leicht unübersichtlich wird an einigen Stellen.
Danke euch allen für die Hilfe!
-
Wenn du meinen Link gelesen hättest wärst du selbst drauf gekommen.
-
Djinndrache schrieb:
Ich werde jedenfalls erstmal kräftig den Code aufräumen bevor ich was neues mache, da es mittlerweile doch schon leicht unübersichtlich wird an einigen Stellen.
Das ist eine gute Idee, und das sollte man immer wieder machen, nicht nur alle Jubeljahre mal, wenn man auf die Nase gefallen ist
Zu den #includes etc. auch folgendes: http://www.gotw.ca/gotw/007.htm