Designfrage: Spezialisierte Methode



  • Hallo!

    Ich habe folgende Klassen:

    class Texture {
       virtual void foo();
    };
    
    class D3DTexture : public Texture {
       void d3dMethod();
    };
    
    class OGLTexture : public Texture {
       void oglMethod();
    };
    
    class RenderSystem {
       virtual void setTexture(Texture* t) = 0;
    };
    
    class D3DRenderSystem : public RenderSystem {
       virtual void setTexture(Texture* t) {
          // Ein D3DRenderSystem kriegt hier IMMER eine D3DTexture rein.
          // Hier brauche ich Zugriff auf D3D spezifische Methoden:
          D3DTexture* d3dTex = static_cast<D3DTexture*>(t);
          d3dTex->d3dMethod();
       }
    };
    

    Die Frage steht im Grunde schon im Code. Ich habe eine Oberklasse RenderSystem und konkrete RenderSysteme, zb. D3DRenderSystem oder OGLRenderSystem. Dann habe ich noch eine Oberklasse Texture und konkrete Subklassen wie D3DTexture. Ein D3DRenderSystem arbeitet IMMER nur mit D3DTextureS zusammen.

    Meine Oberklasse RenderSystem hat die Methode setTexture(), da prinzipiell JEDES RenderSystem eine Textur setzen kann. In der Implementierung, hier also D3DRenderSystem::setTexture(), brauche ich dann Zugriff auf RenderSystem spezifische Methoden der Texture. Ein D3DRenderSystem kriegt bei setTexture(Texture* t) also IMMER eine Textur vom Typ D3DTexture rein, drum caste ich die auf D3DTexture und rufe dann die D3D spezifische Methode auf.

    Ist das in Ordnung oder könnte man das irgendwie anders machen?



  • Das ist nicht ganz in Ordnung. Wenn setTexture() immer ein abgeleitetes Objekt bekommt, könnte es auch dieses als Parametertypen haben. Polymorphie geht dann nicht mehr, allerdings ist das möglicherweise auch nicht nötig, weil D3DRenderSystem bekannt ist.

    Aber wir hatten was Ähnliches erst gerade: http://www.c-plusplus.net/forum/287913-40



  • Ich weiß, das Problem ist ähnlich, aber nicht ganz das selbe.
    Ich brauche in einer Basisklasse die Methode, da ich unabhängig vom konkreten RenderSystem die Textur setzen will. Sprich ganz oben in der Abstraktion sage ich nur: renderSystem->setTexture(texture); Welches RenderSystem gerade aktiv ist, ist mir egal.
    D.h. setTexture MUSS in die Oberklasse. Kann man meinen Fall nicht einfach als Spazialisierung sehen? Ich mein ich benutz ja nicht mal dynamic_cast<>. Die konkreten Render Systeme kriegen alle eine Textur, nur wissen sie eben genau WAS für eine Textur reinkommt => static_cast



  • DesignFrager2 schrieb:

    Sprich ganz oben in der Abstraktion sage ich nur: renderSystem->setTexture(texture); Welches RenderSystem gerade aktiv ist, ist mir egal.

    Nein ist es dir nicht. Hast du eine D3DTextur MUSST du ein D3DRenderSystem haben. Es ist wieder eine LSP Verletzung und genau das gleiche Problem wie das letzte.
    Mal nebenbei gefragt, reicht dir nicht eigentlich eine Compilezeit Polymorphie? Oder willst du wirklich das RenderSystem zur Laufzeit ändern?



  • brotbernd schrieb:

    DesignFrager2 schrieb:

    Sprich ganz oben in der Abstraktion sage ich nur: renderSystem->setTexture(texture); Welches RenderSystem gerade aktiv ist, ist mir egal.

    Nein ist es dir nicht. Hast du eine D3DTextur MUSST du ein D3DRenderSystem haben. Es ist wieder eine LSP Verletzung und genau das gleiche Problem wie das letzte.

    Das ist richtig. Wenn renderSystem ein D3DRenderSystem ist, dann wird texture vom Typ D3DTexture sein. Aber das soll mich an dieser nicht interessieren. Ich habe hier nur einen Zeiger auf ein RenderSystem. Welches es gerade ist, darf mich nicht interessieren. Da bleibt mir ja dann keine Wahl, als eine generische setTexture() Methode in der Oberklasse anzubieten.

    brotbernd schrieb:

    Mal nebenbei gefragt, reicht dir nicht eigentlich eine Compilezeit Polymorphie? Oder willst du wirklich das RenderSystem zur Laufzeit ändern?

    Es soll schon zur Laufzeit passieren, denn unter Windows könnte sich dann der Benutzer zwischen DirectX oder OpenGL entscheiden.



  • Das Problem ist exakt das Selbe wie im andren Thread und ich sag auch hier: Wenn du mich fragst ist Abstraktion auf dem Level auf dem du sie hier zu betreiben versuchst sinnlos. Vor allem mit OpenGL gibts da aufgrund des kaputten Objektmodells nur Probleme. Wenn du einfach auf höherer Ebene kapselst lösen sich all diese Probleme in Luft auf und die Performance freut sich auch.



  • Ich hoffe brotbernd liest das hier, denn er hat (neben tunichtgut) die hilfreichsten Antworten in meinem alten Thread geliefert.

    Das hier war sein Vorschlag:

    class RenderSystem 
     { 
    public: 
         virtual void MachWas() const = 0; 
     }; 
    
    class RenderTarget 
     { 
    public: 
         void TuWas() 
         { 
             GetRenderSystem()->MachWas(); 
             Schwipp(); 
         } 
    private: 
         virtual void Schwipp() = 0; 
         virtual const RenderSystem* GetRenderSystem() const = 0; 
     }; 
    
    class D3RenderWindow; 
    class D3RenderSystem : public RenderSystem 
     { 
    public: 
         void MachWas() const { std::cout << "D3RenderSystem macht was\n"; } 
         void Schwapp(D3RenderWindow& window){} 
    
     }; 
    
    class D3RenderWindow : public RenderTarget 
     { 
    public: 
         D3RenderSystem mRenderSystem; 
         void Schwipp() 
         { 
             mRenderSystem.Schwapp(*this); 
         } 
         const RenderSystem* GetRenderSystem() const 
         { 
             return &mRenderSystem; 
         } 
     };
    

    Das ist auch schon ziemlich clever, denn ich habe sowohl Zugriff auf die Oberklasse RenderSystem in den RenderTargets als auch Zugriff auf das konkrete RenderSystem in den konkreten RenderTargets.
    brotbernd hat aber mein Grundproblem einfach gestrichen: Er hat einfach der Methode RenderSystem::tuWas() den Parameter entfernt. In diesem alten Thread als auch hier brauche ich aber einen Parameter, denn jedes RenderSystem kann eine Textur setzen, sprich: RenderSystem::setTexture(Texture* t);

    Wenn ich setTexture in die konkreten Subklassen verschiebe, also z.B. D3DRenderSystem::setTexture(D3DTexture* t), dann kann ich nicht mehr über die Basisklasse drauf zugreifen. Dann bringt mir die ganze Oberklasse nichts mehr:/



  • Also erstmal muss ich sagen, dass ich auch eher der Ansicht bin, dass das Abstraktionslevel zu niedrig ist. Du hast allgemeine Konzepte für Target, Systeme und Texturen, kannst aber immer nur die jeweils passenden mit einander kombinieren. Du abstrahierst etwas um es sofort wieder zu konkretisieren. Naja aber davon scheinst du ja nichts wissen zu wollen.
    Zu der aktuellen Frage weiß ich jetzt spontan auch nichts zu sagen, zumal ich überhaupt nicht mehr blicke was ein RenderSystem und target und textur ist (Wieso setzt man eine Textur auf ein Rendersystem?). Wer ist denn z.B. Erzeuger und Besitzer von einer Textur? Vielleicht kannst du ja einen abstrakten Texturerzeuger mit passenden Parametern übergeben, mit dem sich ein RenderSystem die gewünschte konkrete Textur erzeugen lässt. Naja, klingt irgendwie nicht wirklich sinnvoll. Ich glaub wirklich, dass du dir das Leben unnötig schwer machst.


Anmelden zum Antworten