Vererbung: Basisklasse soll neu definierte Methode auch intern verwenden
-
Hallo,
Ich entschuldige mich schon einmal im Voraus, meine Frage wurde bestimmt schon des öfteren beantwortet - leider weiß ich nicht, wonach ich suchen muss. Bitte sagt mir auch, wenn ich die C++ Terminologie nicht korrekt verwende.
Ich habe eine Klasse geschrieben, die mir als Vorlage für Animationen dienen soll. Sie sieht ungefähr so aus:
class animationwindow { //... public: //... void handleEvents(){/*handle nichts*/}; void repaint(){/*zeichne nichts*/}; void mainloop(){ while(1) { handleEvents(); repaint(); } }; };
Die Methoden "handleEvents" und "repaint" sollen dann in der tatsächlichen Animation neu definiert werden.
Nun definiere ich folgende Animation, die von "animationwindow" erbt und die "repaint" Methode überschreiben soll:
class anim : public animationwindow { //... public: //... void repaint() const { //zeichne einen frame der animation }; };
Wenn ich dann allerdings im Hauptprogramm die geerbte Methode "mainloop()" der Klasse "anim" aufrufe, wird die "repaint" Methode der Basisklasse verwendet und nicht die neu definierte. Ich habe schon viel mit virtual, const, etc. herumgespielt, verstehe aber offensichtlich noch nicht genug davon. Wenn ich die Inhalte der "mainloop()" Methode explizit im Hauptprogramm implementiere, funktioniert es wie es soll, ich hätte aber gern eine extra Methode dafür.
Wie kann ich also der Basisklasse klarmachen, dass sie auch intern die neu definierte Methode der abgeleiteten Klasse verwenden soll?
Ich würde mich freuen, wenn mir jemand einen kleinen Wink in die richtige Richtung geben könnte, mir sagt, wonach ich suchen sollte oder mir sogar einen richtiggestellten Beispielcode posten könnte - Sofern das was ich da mache überhaupt sinnvoll ist. Alternativlösungen sind auch herzlich willkommen.
Vielen Dank schon mal.
Mit besten Grüßen,
Stefan
-
stfn schrieb:
...Wie kann ich also der Basisklasse klarmachen, dass sie auch intern die neu definierte Methode der abgeleiteten Klasse verwenden soll?...
Das Schlüsselwort virtual ist dein Freund.
Und wenn dein "animationwindow" nur als Basisklasse dienen soll, ohne direkt verwendet werden zu können, dann kannst du die Methoden auch als sogenanntes "pure virtual" [Schreibweise später im Text] deklarieren (Dies entspricht in anderen Sprachen dem "Interface"). Alle Klassen die als Basisklasse dienen sollten zudem im Regelfall einen virtuellen Destruktor verwenden.Kurzes Beispiel und Schreibweise:
class Basis { public: int foo1(); // Normale Methode virtual foo2(); // Virtuelle Methode virtual foo3() = 0; // Pure-Virtuelle Methode virtual ~Basis(); // Bei Basisklassen im Regelfall immer virtueller Destruktor! }
Pur-Virtuelle Methoden haben keine Definition, sobald eine pure virtuelle Methode verwendet wird, kann keine Instanz der Klasse selbst erzeugt werden (Wohl aber kann man weiterhin die Zeiger der Basisklasse zum Verwalten von den konkret davon abgeleiteten verwenden. Falls man keine pur virtuelle Methode hat, aber eben dieses Verhalten erzwingen möchte, so kann man den Destruktor als pure virtuell deklarieren: hier ist aber die Deklaration egal wie zu machen (also mindestens {} ).
"virtual" wird mitvererbt. Sprich: In einer Basisklasse für eine Methode gesetzt gilt dies auch für die abgeleiten Klassen, auch wenn dort virtual nicht mehr erwähnt wird.
cu André
-
Super, hat geklappt. 103 Dank.
Das Schlüsselwort "virtual" und das Weglassen des Schlüsselwortes "const" hinter "anim::repaint()" machten den Unterschied.
Stefan
-
stfn schrieb:
Super, hat geklappt. 103 Dank.
Das Schlüsselwort "virtual" und das Weglassen des Schlüsselwortes "const" hinter "anim::repaint()" machten den Unterschied.
Das const hinter einer Funktion ist schon richtig, sofern diese Funktion nichts am Objektzustand ändert. Das hat mit dem virtual nichts zu tun, nur habe ich mich hier der Einfachheit halber nur um die virtual-Beschreibung gekümmert.
-
Nachdem ich die entsprechenden Methoden "virtual" gesetzt hatte, blieb das Problem weiterhin bestehen. Erst als ich das "const" weggelassen habe, hat das Programm gemacht was ich wollte.
-
stfn schrieb:
Nachdem ich die entsprechenden Methoden "virtual" gesetzt hatte, blieb das Problem weiterhin bestehen. Erst als ich das "const" weggelassen habe, hat das Programm gemacht was ich wollte.
Dann hattest Du vermutlich in der Basisklasse const und in der abgeleiteten nicht, oder umgekehrt. Denn dann hast Du nicht eine virtuell überschriebene Funktion, sondern zwei völlig voneinander unabhängige.
Also: Mit const in beiden Klassen solltest Du kein Problem haben.
-
Das liegt einfach daran, dass die Funktion der Basisklasse nicht const ist. Somit hat die const-Variante in der abgeleiteten Klasse eine neue Methode implementiert, da ja const zum Namen der Methode gehört. Nur wenn beide const oder nicht const sind funktioniert es mit virtual wie gewollt.
-
stfn schrieb:
das Weglassen des Schlüsselwortes "const" hinter "anim::repaint()" machten den Unterschied.
anim::repaint() const
undanim::repaint()
sind zwei verschiedene methoden. wenn du in der basisklasse repaint als const deklarierst, dann hast du auch kein problem damit, die funktion in der abgeleiteten klasse zu überschreiben. die methode, die du überschreiben willst, muss dieselbe signatur haben wie die methode in der basisklasse.*
du wunderst dich ja schließlich auch nicht darüber:class Base { public: virtual void foo (int) {} }; class Derived : Base { virtual void foo (double) {} }; Base* b = new Derived; b->foo(42);
b->foo ruft natürlich nicht Derived::foo(double) auf.
das einzige, was in der abgeleiteten klasse hier passiert, ist das Base::foo verdeckt wird.*(nur kovariante rückgabetypen sind erlaubt)
-
Alles klar, ich verstehe. Nochmals vielen Dank für die zahlreichen Antworten. Ich schau bestimmt bald mal wieder vorbei.
Stefan