Muster um Mehrere virtuelle Funktionen aufrufen

Programmiersprachen, APIs, Bibliotheken, Open Source Engines, Debugging, Quellcode Fehler und alles was mit praktischer Programmierung zu tun hat.
Antworten
Benutzeravatar
Jonathan
Establishment
Beiträge: 2874
Registriert: 04.08.2004, 20:06
Kontaktdaten:

Muster um Mehrere virtuelle Funktionen aufrufen

Beitrag von Jonathan »

Moin,

wenn ich in C++ eine Klassenhierarchie mit virtuellen Funktionen habe, wird ja immer die "unterste" Funktion aufgerufen. Die Spezialisierung überschreibt das Verhalten das Basisklasse. Nun gut. Aber sagen wir mal, die virtuelle Funktion sei eine Art Ereignis, und auch eine Klasse irgendwo in der Mitte der Hierarchie soll darauf reagieren und Code ausführen - wie mache ich das am elegantesten? Ich hätte gerne ein Verhalten wie bei Konstruktoren, wo alle in definierter Reihenfolge aufgerufen werden.

Mein Beispiel gerade: Widget Klassen und Sichtbarkeit. Sagen wir, ich habe ein Widget, davon abgeleitet eines, das einen Rahmen anzeigt (Sprite wird gerendert) und am Ende ein Text-Widget, das den Text hinzufügt. Ändert sich die Sichtbarkeit, müssen sowohl das Sprite als auch der Text umgeschaltet werden. Standardmäßig würde jetzt aber nur der Text umgeschaltet, weil nur die unterste Funktion ausgeführt wird.

Verschiedene mögliche Ansätze:

- Das Text-Widget ruft die virtuelle Funktion der Basisklasse auf. Funktioniert, ist aber nicht robust, weil eine andere, neue Klasse diesen Aufrufe vergessen könnte. Das möchte ich gerne vermeiden.
- Das Rahmen-Sprite deklariert die Überladung als final und hat eine neue virtuelle Funktion (update_visibility_internal), die sie dann aufruft. Funktioniert, ist robust, aber jetzt heißen meine Funktionen plötzlich anders. Noch lustiger wird es, wenn das über mehrere Ebenen mehrmals nacheinander passiert (update_internal_internal()).
- Ein komplettes Event-System, in dem sich Klassen registrieren können. Funktioniert und ist sehr flexibel, aber auch irgendwie sehr viel zusätzlicher Code. Außerdem haben virtuelle Funktionen den Vorteil, das man nicht vergessen kann sie zu implementieren.

Ich tendiere gerade am ehesten zur zweiten Variante, aber besonders happy bin ich damit noch nicht. Gibt es noch irgendwelche anderen Ideen?
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
Benutzeravatar
Lord Delvin
Establishment
Beiträge: 631
Registriert: 05.07.2003, 11:17

Re: Muster um Mehrere virtuelle Funktionen aufrufen

Beitrag von Lord Delvin »

Die erste Variante ist wahrscheinlich was du willst; für deinen Anwendungsfall wirst du aber in keiner mir bekannten Sprache Toolsupport wie bei Konstruktoren bekommen (implizite calls z.B.). Ein Mittelding ist Visitor-Pattern ohne walks oder dispatches in der Abstrakten Visitorbasisklasse. Dann kannst du wo du's brauchst mit einem Staticcast explizit nach oben delegieren. Klingt mir ohnehin ein bisschen nach Visitor.

Die Idee mit den Events fand ich im ersten moment plausibel, im zweiten aber nicht mehr, weil es bedeutet, dass dasselbe Objekt mehrfach auf ein Event lauscht. Da brauchst du vermutlich bei vielen Eventsystemen eine Art Adapterobjekt, um das überhaupt machen zu können.

Wenn du dich selbst zwingen willst die calls zu machen kannst du auch ein Pseudotyp (typ/konstruktor privat für die Wurzel deiner Hierarchie) zurückgeben und so immer als letztes den Parentcall rausgeben; hat aber etwas runtime overhead. Du kannst auch versuchen dich selbst zu zwingen als erstes immer den super call zu machen; normalerweise bekommt man das hin ;)

Was dir in jedem Fall passieren kann ist, dass überraschend viel Code generiert wird, weil du mindestens eine Implementierung pro vtable slot brauchst aber die super calls aus dem Stack static calls sind und damit inline kandidaten. Keine Ahnung ob das für dich relevant ist; ggf. schauen ob C++ noinline attribute hat; würde ich aber erst machen wenn da >100mb executable rauskommen :)
XML/JSON/EMF in schnell: OGSS
Keine Lust mehr auf C++? Versuche Tyr: Get & Get started
Antworten