Vererbung von Klassen über mehrere Header ( Problem )



  • Ich habe folgendes vor:

    [ Main.cpp ]

    #include "Engine.h"
    
    CEngine g_Engine;
    

    [ Engine.h ]

    #include "Direct3D.h"
    
    class CEngine
    {
    
    };
    

    [ Direct3D.h ]

    #include "Engine.h"
    
    class CDirect3D : public CEngine
    {
    
    };
    

    Leider bekomme ich so einen Fehler:

    > error C2504: 'CEngine' : base class undefined <<

    Ich denke ich habe dort etwas falsch verstanden und
    inkludiere falsch oder nutze die Vererbung der Klassen
    falsch. Allerdings würde ich es schon gerne so haben, das
    ich über die Main auf die Engine Klasse zugreife und
    die Engine Klasse einen Zugriff auf die Direct3D Klasse
    hat und die im gegenzug eine Vererbung auf die Engine
    Klasse hat.

    Mfg.



  • Warum brauchst du in der Engine.h ein #include "Direct3D.h" ? Deine Header includen sich gegenseitig und das ist wohl die Ursache für den Problem und die merkwürdige Fehlermeldung.



  • Ich möchte logisch agieren und in der Engine z.B. die Fenster-Verwaltung durchführen und diese Engine greift dann auf die Direct3D zu z.B. um das Fenster neu zu Initialisieren zu können. Allerdings soll Direct3D auf Engine Variablen zurückgreifen können, z.B. m_Width, m_Height.

    Sowas muss doch möglich sein, ansonsten zerbricht mein ganzes Konzept. Denn später möchte ich meinen CPlayer von CMap erben lassen und CIntersect von CPlayer ect.



  • Die Lösung dürften wohl eher virtuelle Funktionen sein. So ist dein Konzept jedenfalls zerbrochen.



  • Zigeuner736 schrieb:

    Sowas muss doch möglich sein, ansonsten zerbricht mein ganzes Konzept. Denn später möchte ich meinen CPlayer von CMap erben lassen und CIntersect von CPlayer ect.

    Das Konzept würde ich wirklich überarbeiten. Vererbung stellt eine Ist-Beziehung da. Du erweiterst und spezialisierst damit eine andere Klasse. Ein Player ist aber keine Map und ein Intersect ist auch kein Player.

    Hast du zufällig C++ von A bis Z gelesen? Da wird der Zusammenhang nämlich genau falsch erklärt: https://www.c-plusplus.net/forum/272350-full



  • Es wäre so schön zu behaupten, das dieses Buch Schuld für mein Versagen ist. Allerdings liegt es rein an mir, ich habe C++ nie richtig mit einem Buch gelernt, aber auch nicht über Tutorials oder so etwas. Ich habe es mir versucht selbst bei zu bringen und eine kleine Voxel Engine ( Spiel ) geschrieben, das Minecraft imitiert. Allerdings wollte ich das Projekt neu starten, um eine bessere Struktur zu erreichen und mehr nach Regeln zu arbeiten. Ich wollte dabei dieses Vererbung's Prinzip anwenden, allerdings habe ich da ziemlich was falsch verstanden. Es wäre wirklich schön gewesen, wenn z.B. Direct3D direkt auf die Member von Engine zugreifen könnte und Engien dann auf Funktionen von Direct3D. Gut, leider scheint dies nicht möglich zu sein. Ich sollte das ganze mal überdenken, dachte ich erspare mir diese ganzen Funktions-Parameter, besonders weil ich ein Code von 8000 Zeilen-Code habe in der Engine ..



  • Zigeuner736 schrieb:

    Es wäre wirklich schön gewesen, wenn z.B. Direct3D direkt auf die Member von Engine zugreifen könnte und Engien dann auf Funktionen von Direct3D. Gut, leider scheint dies nicht möglich zu sein. Ich sollte das ganze mal überdenken, dachte ich erspare mir diese ganzen Funktions-Parameter, besonders weil ich ein Code von 8000 Zeilen-Code habe in der Engine ..

    Doch! Es ist möglich, aber so wie du das offenbar vorhast sieht es nicht nach einem guten Klassendesign aus.
    Man kann es schon so machen, aber mit sehr hoher Wahrscheinlichkeit wären dann deine Include-Probleme dann nur der Anfang eines langen Weges durchs Tal der Tränen 😞
    Die hier erwähnte "ist ein"-Frage ist auf jeden Fall eine gute Richtschnur, anhand der man erkennen kann, ob man vielleicht auf dem Holzweg ist:
    Ist die abgeleitete Klasse auch ein solches Ding wie das von dem sie erbt? Wenn nicht, handelt man sich wahrscheinlich Probleme ein (auch wenn es da Ausnahmen gibt).

    Das "überdenken" würde ich dir also auch nahelegen. Allerdings kann es nicht schaden auch zu verstehen, was bei deinem Include überhaupt schiefgelaufen ist:

    In solchen Fällen einfach mal Schritt für Schritt durchgehen, was da eigentlich inkludiert und kompiliert wird, Dann ist die Fehlermeldung auch leicht nachvollziehbar.
    #include -Anweisungen sind schließlich nicht viel mehr als ein Copy-Paste der Datei an die Stelle, an der das #include steht:

    // Main.cpp:
    // #include "Engine.h"
    
    // Engine.h
    //#include "Direct3D.h"
    
    // Direct3D.h
    class CDirect3D : public CEngine
    {
    };
    
    // Rest von Engine.h
    class CEngine
    {
    };
    
    // Rest von Main.cpp
    CEngine g_Engine;
    

    Beachte Zeile 8: CDirect3D erbt hier von CEngine , obwohl CEngine noch nicht deklariert oder definiert wurde, wobei letzteres notwendig ist,
    um von der Klasse erben zu können. Du müsstest also dafür sorgen, dass CEngine vor CDirect3D definiert wird. Also entweder:

    - kein #include "Direct3D.h" in "Engine.h", stattdessen #include "Engine.h" in "Direct3D.h"
    - oder: #include "Direct3D.h" erst nach der Definition von CEngine in "Engine.h" (nicht so schön)
    - oder (wahrscheinlich besser): Komposition statt Vererbung: Ist CDirect3D wirklich eine "Engine" oder nicht vielmehr ein API-Interface? Wie wäre z.B. sowas hier?

    class CGraphicsAPI
    {
       public:
          virtual void open_window() = 0;
          virtual void draw_something() = 0;
          virtual void close_window() = 0;
    };
    
    class CDirect3D : GraphicsAPI
    {
       public:
          void open_window() override {  ... ID3D11DeviceContext* ... }
          void draw_something() override { ... context->draw(...) ... }
          void close_window() override { ... context->Release() ... }
    };
    
    class COpenGL : GraphicsAPI
    {
       public:
          void open_window() override { ... wglCreateContext(...) ... }
          void draw_something() override { ... glDrawBuffers(...) ... }
          void close_window() override { ... wglDeleteContext(...) ... }
    };
    
    class CEngine
    {
       // "Komposition":
       GraphicsAPI* graphicsAPI;
    };
    

    ... nur so als Beispiel, wie man so etwas abstrahieren könnte.
    Damit löst sich dann auch dein Include-Problem auf.

    Gruss,
    Finnegan



  • Zigeuner736 schrieb:

    Es wäre wirklich schön gewesen, wenn z.B. Direct3D direkt auf die Member von Engine zugreifen könnte und Engien dann auf Funktionen von Direct3D.

    Das kannst du schon machen (mit z.b. public membern), ist dann halt kacke.

    Wenn du von ueberall auf alles zugreifst, wirst du sehr schnell den Ueberblick verlieren, wann wo welche Daten gelesen und geschrieben werden. Eine sinnvolle Klassenstruktur ist eines der Hilfsmittel um deine 8000 Zeilen sinnvoll zu ordnen. Du solltest also z.b. deine Engine noch etwas weiter aufteilen.



  • Vielen Dank für die vielen interessanten Nachrichten.
    Ich werde mich mal mit dem Thema mehr beschäftigen und
    mein Konzept ein bisschen umgestalten. Eine kleine Frage
    hätte ich noch. Wie sieht es denn aus, wenn ich in meiner
    Engine Class einen Pointer zu der Klasse Direct3D erstelle
    und im Constructor ein Parameter mit "this" für die Engine
    Klasse angebe, wäre so etwas machbar ? Und wie sieht es
    aus, ist das schlimm bezüglich public ect. ?


Log in to reply