Überschreibung von Methoden bei Vererbung



  • Meine Klasse A überschreibt statische Funktionen ihrer Basisklasse B. Diese Klasse A verwendet eine Methode aus der Basisklasse die mit den neu definierten Funktionen arbeiten soll. Leider werden die nicht überschriebenen, alten Funktionen der Basisklasse verwendet. Meinen Code habe ich auf das Grundlegende Problem reduziert.

    A.h
    class A : public B
    {
    public:
    static void initContent(void);
    };

    B.h
    class B
    {
    public:
    static int start(WinMainStuff);
    static void initContent(void);

    };

    A.cpp
    int WINAPI WinMain(WinMainStuff){
    A::start(WinMainStuff);
    }
    void A::initContent(){
    std::cout << "A" << std::endl;
    }

    B.cpp
    void B::initContent(){
    std::cout << "B" << std::endl;
    }

    int B::start(WinMainStuff)
    {
    initContent();
    }

    Ergebnis des Codes ist B, sollte aber A sein.
    Wie kann ich dieses Problem lösen?

    Im Vorfeld bedanke ich mich an jeden, der mir versucht zu helfen.



  • Hi,

    Vererbung spielt bei statischen Methoden überhaupt keine Rolle. Du überschreibst dementsprechend hier keine Methoden, sondern du verdeckst sie nur. Wenn du die statische Methode von A aufrufen möchtest, dann machst du das mit A::initContent();
    Denk aber daran, dass das nichts mit Polymorphie zu tun hat. Dafür müsstest du die Methode virtuell deklarieren.

    mfG
    KaPtainCugel



  • Wie soll ich von B aus denn A aufrufen? B ist praktisch nur eine Schablone, und enthält keine Informationen über A. A füllt B sozusagen mit Inhalt.



  • Nochmal: Statische Funktionen haben mit Vererbung gar nix zu tun! Anstatt in ne Klasse könntest du die Funktionen auch in nen namespace packen!
    Du suchst wohl wirklich "virtual".



  • Der Zweck meiner Klasse ist es ein Grundgerüst für das Arbeiten mit DirectX zu schaffen. Ich möchte praktisch die ganzen Funktionen die nah an der Hardware dran sind in einer Klasse abkapseln.

    Eine neue Klasse soll auf die Funktionen meiner Schablone zugreifen können - das kriege ich ja hin. Nun müsste ich aber auch zurück verweisen können ohne die neue Klasse explizit benennen zu dürfen (das wollte ich mit Vererbung lösen), denn diese könnte "Main.cpp", "Test.cpp", oder anders heißen.

    Mit dem Stichwort virtual habe ich mich schon beschäftigt - nur verstehe ich leider nicht genau wie ich damit arbeiten soll. Könnt ihr mir erklären (am liebsten anhand meines Beispiels) wie ich damit arbeiten soll?



  • Schifty schrieb:

    Mit dem Stichwort virtual habe ich mich schon beschäftigt - nur verstehe ich leider nicht genau wie ich damit arbeiten soll. Könnt ihr mir erklären (am liebsten anhand meines Beispiels) wie ich damit arbeiten soll?

    Ich glaube du solltest dich nochmal mit den C++ Grundlagen beschäftigen, bevor du dich an DirectX wagst... Zumal ich das Design ohnehin stark anzweifel (Selten machen Klassenhirachien mit rein statischen Funktionen Sinn).

    In deinen Fall ist vermutlich dynamische (virtual) oder statische (Templatetechniken) Polymorphie das angebrachteste.

    Eine virtuelle Funktion kann nicht statisch sein, und führt dazu das der Code von der Funktion aufgerufen wird, die in der Hirachie am nächsten zur konkreten Instanz steht.

    Beispiel:

    class A {
      virtual void foo1() { std::cout << "A::foo1()" << std::endl; }
      virtual void foo2() { std::cout << "A::foo2()" << std::endl; }
      virtual ~A() {} // Destruktor virtual bei einer Basisklasse, wenn löschen
                      // über Basisklassenzeiger möglich sein soll.
    };
    
    class B : public A {
      virtual void foo1() { std::cout << "B::foo1()" << std::endl; }
    };
    
    class C : public B {
      virtual void foo2() { std::cout << "C::foo2()" << std::endl; }
    };
    
    int main()
    {
      A * a = new A();
      A * b = new B();
      A * c = new C();
    
      a->foo1;
      a->foo2;
      b->foo1;
      b->foo2;
      c->foo1;
      c->foo2;
    
      delete a;
      delete b;
      delete c;
    }
    

    Ausgabe:

    A::foo1()
    A::foo2()
    B::foo1()
    A::foo2()
    B::foo1()
    C::foo2()
    

    Es wird immer der Code aufgerufen der "am nächsten" in der Hirachie zum konkreten Typen steht. Wenn du virtual weglässt würde immer (da über A-Zeiger aufgerufen) die Implementierung der Klasse A aufgerufen werden.

    Statische Polymorphie führt hier aber wohl noch etwas zu weit.



  • Die Java Monkey Engine macht es genau so! Die gibt eine Klasse SimpleGame vor, diese muss man erweitern - sowohl init als auch draw müssen dabei überschrieben werden - dann kann man loslegen sein Spiel zu programmieren. Genau so wollt ich das bei meinem Projekt auch machen. Insofern macht diese recht flache statische Klassenhierarchie schon Sinn!

    Ich will einfach nur den gesamten Inhalt meiner Basisklasse in anderen Klassen verfügbar machen und dort Methoden überschreiben. Warum ist in C++ alles so kompliziert? Ich glaube statische Polymorphie ist was ich suche... mal nachlesen!



  • Schifty2 schrieb:

    Die Java Monkey Engine macht es genau so!

    Und jetzt? Die Java-Standardbibliothek erbt auch Stack von Vector. Was sagt uns das?

    Schifty2 schrieb:

    Insofern macht diese recht flache statische Klassenhierarchie schon Sinn!

    Nein, macht sie nicht.

    Erstens können statische Methoden nicht polymorph überschrieben werden. Das würde auch gar keinen Sinn machen, Laufzeitpolymorphie ist schliesslich objekt- und nicht klassenbezogen. Zweitens gibt es in C++ freie Funktionen, die sind sehr oft besser geeignet als statische. In Java hat man die nicht.

    Schifty2 schrieb:

    Ich will einfach nur den gesamten Inhalt meiner Basisklasse in anderen Klassen verfügbar machen und dort Methoden überschreiben. Warum ist in C++ alles so kompliziert?

    Das Beschriebene ist kein bisschen kompliziert. Aber man sollte sich vielleicht vorher mit der Theorie auseinandersetzen. Du kannst nicht annehmen, dass wenn du Java kennst, sich alles 1:1 auf C++ übertragen lässt und du nichts mehr lernen musst. In C++ sind die Konzepte grundlegend anders, auch wenn oberflächlich viele Gemeinsamkeiten bestehen.

    Schifty2 schrieb:

    Ich glaube statische Polymorphie ist was ich suche... mal nachlesen!

    Du scheinst ja wirklich Freude am Wort "statisch" zu haben. Aber vorweg: Statische Polymorphie hat nichts mit static zu tun und ist etwas komplett anderes, als du dir darunter vorstellst.



  • Schifty2 schrieb:

    Die Java Monkey Engine macht es genau so! Die gibt eine Klasse SimpleGame vor, diese muss man erweitern - sowohl init als auch draw müssen dabei überschrieben werden - dann kann man loslegen sein Spiel zu programmieren. Genau so wollt ich das bei meinem Projekt auch machen. Insofern macht diese recht flache statische Klassenhierarchie schon Sinn!

    Nein, macht sie nicht. http://www.jmonkeyengine.com/doc/com/jme/app/BaseGame.html BaseGame.initGame() usw. sind abstract und nicht static. Java abstract == C++ virtual ... = 0; (pure virtual)



  • Ja hab auch gemerkt das es da doch anders lief, analog dazu habe ich es einfach umgeschrieben und jetzt passt es auch!

    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){

    TestCase* test = new TestCase;
    test->start(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
    }

    void TestCase::initContent(){....}

    void TestCase::drawContent(){...}

    }



  • Noch was, das du komplett neu lernen musst, wenn du von Java nach C++ umsteigst: In C++ ist Wert- und nicht Referenzsemantik vorrangig. Die dynamische Speicherverwaltung ist manuell; was du mit new anforderst, musst du mit delete freigeben (analog new[] und delete[] ), sonst hast du ein Memory Leak. Allerdings kannst du unter Einsatz geeigneter Klassen die manuelle Speicherverwaltung auf ein Minimum reduzieren (RAII).

    Falls initContent() die Instanz initialisieren soll, solltest du stattdessen Konstruktoren nehmen.

    Und jetzt schau dir endlich ein C++-Buch an, mit Java in C++ wirst du unweigerlich scheitern!


Anmelden zum Antworten