Ist hier dynamic_cast ok?
-
dot schrieb:
caster2 schrieb:
Ganz vermeiden ist unmoeglich.
Man könnte es vermeiden sinnlose Wrapper zu schreiben, dann braucht man auch keine Hacks und spart unnötigen Overhead

Geht nicht. Die Engine soll mit beiden APIs laufen und das erfordert nun mal Abstraktion. Klappt ja bis jetzt auch. Nicht immer schoen, aber es klappt. Schonheitspreise fuer Code gibts eh nicht. Entscheidend ist nur die Qualitaet des Spiels, das man mit dem Code macht.
-
caster2 schrieb:
Die Engine soll mit beiden APIs laufen und das erfordert nun mal Abstraktion.
Ich seh grad nicht wo das Problem liegt, implementier den Renderer der Engine eben einmal mit D3D und einmal mit OpenGL!?
-
dot schrieb:
caster2 schrieb:
Die Engine soll mit beiden APIs laufen und das erfordert nun mal Abstraktion.
Ich seh grad nicht wo das Problem liegt, implementier den Renderer der Engine eben einmal mit D3D und einmal mit OpenGL!?
Wir drehen uns im Kreis. Lass gut sein.
-
caster2 schrieb:
dot schrieb:
caster2 schrieb:
Die Engine soll mit beiden APIs laufen und das erfordert nun mal Abstraktion.
Ich seh grad nicht wo das Problem liegt, implementier den Renderer der Engine eben einmal mit D3D und einmal mit OpenGL!?
Wir drehen uns im Kreis. Lass gut sein.
Er hat schon recht. Baue jeden Renderer für sich auf, und packe dann Fassaden vor jeden Rendertypen, welche das zusammenfassen, was die unterschiedlichen Renderer wirklich gemein haben.
-
Und genau diese Fassade ist RenderSystem.
-
Wie gesagt: Dann ist der Abstraktionsgrad dieser Fassade zu niedrig...
-
caster2 schrieb:
Und genau diese Fassade ist RenderSystem.
RenderSystem * rs = RenderSystem3d(...); //... RenderWindow rw = AnyAvailableRenderWindowCanBeHere(); rs->method(rw); //wie wird sicher gestellt, dass es ein RenderWindow3D ist bzw. woher weißt Du, dass rs auf ein RenderSystem3d zeigt?
-
Tachyon schrieb:
RenderWindow rw = AnyAvailableRenderWindowCanBeHere();
rs->method(rw); //wie wird sicher gestellt, dass es ein RenderWindow3D ist bzw. woher weißt Du, dass rs auf ein RenderSystem3d zeigt?[/cpp]
Garnicht, denn sowas wie AnyAvailableRenderWindowCanBeHere(); habe ich nicht. Wenn das RenderSystem D3D9 ist, gibt es nur D3D9 Render Windows. Ich baue mit Sicherheit nicht einen Wrapper um eine API und darueber dann nochmal einen Wrapper. Halte ich fuer unglaublich haesslich und habe ich bis jetzt auch in noch keiner einzigen Engine gesehen.
-
caster2 schrieb:
Tachyon schrieb:
RenderWindow rw = AnyAvailableRenderWindowCanBeHere();
rs->method(rw); //wie wird sicher gestellt, dass es ein RenderWindow3D ist bzw. woher weißt Du, dass rs auf ein RenderSystem3d zeigt?[/cpp]
Garnicht, denn sowas wie AnyAvailableRenderWindowCanBeHere(); habe ich nicht. Wenn das RenderSystem D3D9 ist, gibt es nur D3D9 Render Windows. Ich baue mit Sicherheit nicht einen Wrapper um eine API und darueber dann nochmal einen Wrapper. Halte ich fuer unglaublich haesslich und habe ich bis jetzt auch in noch keiner einzigen Engine gesehen.
Dann leuchtet mir mal gar nicht ein, warum
RenderSystemeine virtuelle Methode haben muss, welcheRenderWindow-Basisklassen bekommt. RenderWindow-Basisklassenzeiger zu übergeben, wenn eigentlich konkrete RenderWindow-Instanzen erwartet werden halte ich fuer unglaublich haesslich und habe ich bis jetzt auch in noch keiner einzigen Engine gesehen. :p
Btw. hast Du gefragt, obdynamic_castokay ist. So ziemlich alle meinten nein. Eine Antwort hast Du. Wenn Du es trotzdem so machst, dann war die Frage eigentlich überflüssig.Da die mögliche Gesamtmenge an Rendersystemen vermutlich begrenzt sein dürfte, werfe ich jetzt zur Behandlung Deiner konkreteten RenderWindows einfach mal das Visitor-Pattern in den Raum.
-
Tachyon schrieb:
caster2 schrieb:
Tachyon schrieb:
RenderWindow rw = AnyAvailableRenderWindowCanBeHere();
rs->method(rw); //wie wird sicher gestellt, dass es ein RenderWindow3D ist bzw. woher weißt Du, dass rs auf ein RenderSystem3d zeigt?[/cpp]
Garnicht, denn sowas wie AnyAvailableRenderWindowCanBeHere(); habe ich nicht. Wenn das RenderSystem D3D9 ist, gibt es nur D3D9 Render Windows. Ich baue mit Sicherheit nicht einen Wrapper um eine API und darueber dann nochmal einen Wrapper. Halte ich fuer unglaublich haesslich und habe ich bis jetzt auch in noch keiner einzigen Engine gesehen.
Dann leuchtet mir mal gar nicht ein, warum
RenderSystemeine virtuelle Methode haben muss, welcheRenderWindow-Basisklassen bekommt. RenderWindow-Basisklassenzeiger zu übergeben, wenn eigentlich konkrete RenderWindow-Instanzen erwartet werden halte ich fuer unglaublich haesslich und habe ich bis jetzt auch in noch keiner einzigen Engine gesehen. :p
Btw. hast Du gefragt, obdynamic_castokay ist. So ziemlich alle meinten nein. Eine Antwort hast Du. Wenn Du es trotzdem so machst, dann war die Frage eigentlich überflüssig.Da die mögliche Gesamtmenge an Rendersystemen vermutlich begrenzt sein dürfte, werfe ich jetzt zur Behandlung Deiner konkreteten RenderWindows einfach mal das Visitor-Pattern in den Raum.
Na 3mal darfst du raten wieso ich diesen Thread erstellt hab;)
-
caster2 schrieb:
Na 3mal darfst du raten wieso ich diesen Thread erstellt hab;)
Trollversuch?
-
Tachyon schrieb:
caster2 schrieb:
Na 3mal darfst du raten wieso ich diesen Thread erstellt hab;)
Trollversuch?
Klar. War ja so unglaublich provozierend oder polemisch die Frage, ne? Deppen gibts hier...

Immerhin konnte brotbernd und volkard auch was SINNVOLLES beitragen.
-
caster2 schrieb:
Tachyon schrieb:
caster2 schrieb:
Na 3mal darfst du raten wieso ich diesen Thread erstellt hab;)
Trollversuch?
Klar. War ja so unglaublich provozierend oder polemisch die Frage, ne? Deppen gibts hier...

Immerhin konnte brotbernd und volkard auch was SINNVOLLES beitragen.
Der Hinweis auf das Visitor-Pattern ist in Deinem Kontext sinnvoll.
-
Tachyon schrieb:
caster2 schrieb:
Tachyon schrieb:
caster2 schrieb:
Na 3mal darfst du raten wieso ich diesen Thread erstellt hab;)
Trollversuch?
Klar. War ja so unglaublich provozierend oder polemisch die Frage, ne? Deppen gibts hier...

Immerhin konnte brotbernd und volkard auch was SINNVOLLES beitragen.
Der Hinweis auf das Visitor-Pattern ist in Deinem Kontext sinnvoll.
Das mit dem "Trollversuch" hingegen wenig. Das ist eine ziemliche Frechheit.
-
Visitor ist hier im Prinzip das gleiche Problem wie dynamic_cast. Ich muss keinen konkreten Typen suchen, wenn ich schon vorher weiß welcher es ist. Also cast weg, visitor weg, Abstraktion weg und einfach von vornherein den konkreten Typen benutzen. Wenn jemand nur von einer abstrakten Teilschnittstelle abhängen soll, wie die RenderTarget Basisklasse, dann bekommt diese eine RenderSystem Basisklassenreferenz von der Klasse, die den konkreten Typen kennt; nicht andersherum.
Also, das konkrete RenderTarget kennt sein konkretes RenderSystem. Andere Klassen, die nur von der allgemeinen RenderSystem Schnittstelle abhängen, bekommen nur diese zu sehen.
-
@brotbernd: Eine Methode virtual RenderWindow* RenderSystem::createRenderWindow(...) = 0;
macht dann aber nach wie vor Sinn, oder? Ein D3D9RenderSystem gibt dann ein D3D9RenderWindow zurueck, ein OGLRenderSystem ein OGLRenderWindow. Der Benutzer von RenderSystem kriegt dann ein Fenster und muss nicht wissen, welches konkrete Render System/Fenster dahinter steckt. Passt, oder?
-
jap, das ist okay.
-
K. Danke

-
C++ kann kovariante Rückgabetypen, d.h. dass D3D9RenderSystem kann die Create Methode sogar so überschreiben:
virtual RenderWindow* RenderSystem::createRenderWindow(...) = 0 --> D3D9RenderWindow* D3D9RenderSystem::createRenderWindow(...){..}
-
caster2 schrieb:
class Foo { Bar* b: public: Foo(Bar* _b) : b(_b) { } } public FooDerived : public Foo { public: void fooDerivedMethod() { } } class Bar { public: virtual void method(Foo* f) = 0; } class BarDerived : public Bar { public: virtual void method(Foo* f) { // An dieser Stelle weiss ich, dass f IMMER vom Typ FooDerived ist. (BarDerived::method() kriegt IMMER nur FooDerived's) // An dieser Stelle brauche ich Zugriff auf die methode fooDerivedMethod(), die es nur in FooDerived gibt. Ist hier ein Downcast mit dynamic_cast ok? FooDerived* fd = dynamic_cast<FooDerived*>(f); fd->fooDerivedMethod(); // ist das ok? } }Nochmal ganz zurück um das System nochmal zu analysieren. Abgeleitete Klassen von
Foosollen mit Abgeleiteten Klassen vonBarinteragieren. Das ist eigentlich schon mal ein klassischer Fall von Doubledispatch. Dieser Fall stellt aber insoweit eine Besonderheit dar weil nicht jede Abgeleitete Klasse von Foo mit jeder abgeleiteten Klasse von Bar zusammenarbeitet sondern nur eine exakte Kombination. Würde man eine Matrix mit den Dispatchfunktionen erstellen wäre sie sozusagen nur auf der Hauptdiagonalen besetzt. Das sieht man daran das ein dynamic_cast hier funktionieren würde, der genau diesen entsprechenden Fall herausfiltert.
Aber das alles ist garnicht gewollt, da es sich ja hier nicht wirklich um Doubledispatch (oder gar Multidispatch) handelt. Design mäßig ist man da in der Zwickmühle. Ich will eine einheitliche Benutzung des Frameworks über die virtuellen Basisklasse, aber kein Double- oder Multidispatch (was ja eigentlich auch nicht Notwendig ist).
Es gibt keinen Grund OpenGl mit D3D zu mixen. Es wäre jedoch denkbar die beiden Frameworks zur Laufzeit zu verwenden. Nicht unbedingt gleichzeitig, aber schaltbar (ich denk mal das ist gewollt, sonst wäre der ganze Aufwand für die Katz). Damit scheiden Generische Verfahren quasi aus.
Um sowas einigermaßen plausibel umzusetzen muss man soetwas wie einen Abhängigkeitenbaum aufbauen. In diesem Fall istFooz.B abhängig vonBar. In der Basisklasse vonFoowird im Beispiel oben auch schon entsprechend auf die BasisklasseBarverwiesen. In einem Abhängigkeitsbaum müssen aber die konkteten Abhängigkeiten benuzt werden.class FooDerived { BarDerived * b; };in der Klasse
Fookann man noch eine virtuelle Funktion einfügen umBarabzufragen. Die muss dan inFooDerivedüberschrieben werden.class Foo { virtual Bar * GetBar() = 0; }; }In solch einem Abhängigkeitsbaum müssen die Funktionen so angesiedelt sein, das sie über die Abhängigkeiten ihre Parameter mehr oder weniger selbstständig finden. In diesem Fall
FooDerived : public Foo { virtual void fooDerivedMethod() { // hier > BarDerived * b; < benutzen // Der konkrete Typ von Bar ist bekannt ! } BarDerived * b; };Die Methode wird also über
Fooaufgerufen weil dort alles bekannt ist und es wird kein weiterer Parameter benötigt. Das ist eigentlich ja auch Schwachsinn die Methode inBarzu hinterlegen undFooals Parameter zu übergeben wenn die Verknüpfung ohnehin schon vorhanden (und vor allem im richtigen Typ) ist.
So ein Abhängigkeitenbaum kann von der Implementierung her schon sehr aufwendig werden und er funktioniert auch nicht in allen Fällen. Sind die Objekte nur sehr lose gekoppelt und haben keine wirkliche Verbindung muss man tatsächlich die Zuordnung manuell auflösen (z.B. dynamic_cast) oder vielleicht ein virtuelles Funktionsobjekt benutzen. Ein virtuelles Funktionsobjekt ist in diesem Fall ein Objekt was die eigentliche Funktion repräsentiert und eine entsprechende Basisklasse hat, in der Ableitung aber die konkreten Verweise hat. Lohnt sich nur bei hochfrequenten Aufrufen, da die Erstellung sehr kompliziert ist.