'reinterpret_cast' casten von Klassen



  • Hi Leute,

    Mal angenommen ich möchte eine 3D Engine entwickel die sowohl "OpenGL Driver" als auch "Direct3D Driver" anbietet.

    pDevice* = createDevice(OPENGL);
    

    oder

    pDevice* = createDevice(DIRECT3D);
    

    Dann muss der Pointer "pDevice*" entweder vom Typ "class OpenGLDriver" oder "class Direct3DDriver" sein. Das wird aber während der Laufzeit entschieden.

    Ich dachte mir das so:

    class OpenGLDriver {
        public:
            OpenGLDriver();
            void Print() {
                cout << "OpenGL" << endl;
            }
    };
    class Direct3DDriver {
        public:
            Direct3DDriver();
            void Print() {
                cout << "Direct3D" << endl;
            }
    };
    
    int main() {
    
        void* MyDriver = reinterpret_cast<void*>(new OpenGLDriver()); // oder eben "new Direct3DDriver()"
        MyDriver->Print(); // geht nicht weil das leider kein Objekt sindern ein void* ist =(
    
        return 0;
    }
    

    Hat aber leider nicht geklappt.
    Wie macht man das ohne überall im Programm reinterpret_cast aufrufen zu müssen?

    also so will ich das nicht haben weil das überall Zeit kosten würde:

    ((OpenGLDriver*)MyDriver)->Print();
    


  • -Vererbung ?
    -Templates ?



  • Gute, Idee! Aber sind virtuelle Funktionen nicht etwas langsamer als normale?



  • LukasBanana schrieb:

    Gute, Idee! Aber sind virtuelle Funktionen nicht etwas langsamer als normale?

    Nein, nicht unbedingt. Es wird minimal mehr Speicher benötigt. Aber das ist kein Grund sie nicht dort einzusetzen, wo man sie braucht.



  • sie sind kaum langsamer. das device wird normalerweise eh nur einmal am anfang des programms erstellt, da macht es gar nichts aus. du kannst dich aber mal mit policy based design beschäftigen, um eine weitere möglichkeit von c++ kennen zu lernen.


  • Mod

    LukasBanana schrieb:

    Gute, Idee! Aber sind virtuelle Funktionen nicht etwas langsamer als normale?

    Warum sollten sie? Was zusätzliche Zeit kosten kann, ist die Auswahl der richtigen Funktion basierend auf dem dynamischen Typ des Objektes, für das sie aufgerufen wird. Eine solche Auswahl musst du für dein Problem aber in jedem Falle durchführen - darum geht es ja gerade - und es gibt keine Grund anzunehmen, dass der virtuelle Aufrufmechanismus per se langsamer sein wird als etwas Handgestricktes.

    Was das reinterpret_cast hier zu suchen hat, entzieht sich meinem Verständnis.



  • LukasBanana schrieb:

    Gute, Idee! Aber sind virtuelle Funktionen nicht etwas langsamer als normale?

    Bestimmt nicht langsamer als ein manueller Typ-Vergleich und ein nomaler call. 😉

    Gruß,

    Simon2.



  • Okay, danke für eure Hilfe! 🙂

    So funktioniert's jetzt:

    class NullDriver
    {
        public:
            NullDriver() {}
            virtual void Print()
            {
                cout << "Null!" << endl;
            }
    };
    class OpenGLDriver : public NullDriver
    {
        public:
            OpenGLDriver() {}
            virtual void Print()
            {
                cout << "OpenGL!" << endl;
            }
    };
    class Direct3D9Driver : public NullDriver
    {
        public:
            Direct3D9Driver() {}
            virtual void Print()
            {
                cout << "Direct3D9!" << endl;
            }
    };
    
    int main() {
    
        NullDriver* MyDriver;
        MyDriver = reinterpret_cast<OpenGLDriver*>(new OpenGLDriver()); // oder eben wieder "new Direct3DDriver()"
        MyDriver->Print();
    
        return 0;
    }
    

    Gruß Lukas



  • pocily schrieb:

    das device wird normalerweise eh nur einmal am anfang des programms erstellt, da macht es gar nichts aus.

    das war ein denkfehler. es geht ja nicht um virtuelle methoden einer factory, sonder um die des erstellten device. es wird sich aber trotzdem kaum bemerkbar machen und erst recht nicht, wenn du anstattdessen herumcasten muss. das reinterpret_cast kannst du weglassen, aber du solltest einen virtuellen destruktor bei klassen mit virtuellen methoden verwenden, damit der destruktur der subklassen aufgerufen wird, wenn du delete auf einen basisklassenzeiger anwendest.



  • hier mal ein kleines beispiel, wie du es mit virtuellen methoden laufzeit-flexibel und gleichzeitig mit policies compilezeit-flexibel machen kannst:

    #include <iostream>
    #include <string>
    using namespace std;
    
    class IDevice
    {
    public:
        virtual ~IDevice(){}
        virtual void printAPIName() = 0;
    };
    
    template<typename T>
    class Device : public T, public IDevice
    {
        typedef T api_policy;
    
    public:
        void printAPIName() { cout << api_policy::getAPIName(); }
    };
    
    class Direct3DPolicy
    {
    protected:
    	string getAPIName()	{ return "Direct3D API Policy"; }
    };
    
    class OpenGLPolicy
    {
    protected:
    	string getAPIName()	{ return "OpenGL API Policy"; }
    };
    
    int main()
    {
        int iSelection;
        IDevice *myDevice;
    
        cout << "[1]Direct3D\n[2]OpenGL\n";
        cin >> iSelection;
    
        if (iSelection == 1)
            myDevice = new Device<Direct3DPolicy>;
        else if (iSelection == 2)
            myDevice = new Device<OpenGLPolicy>;
        else
            return 1;
    
        myDevice->printAPIName();
    
        //IDevice hat einen virtuellen Destruktor, 
        //denn nur so wird mit "delete einenIDeviceZeiger" auch der 
        //dynamisch angeforderte Device<...> Speicher freigegeben.
        delete myDevice; 
    }
    


  • Hi Lukas,

    zu Deinem Code:

    • lass das 'reinterpret_cast' weg, das ist an dieser Stelle sinnfrei und irreführend.
    • der NullDriver sollte keine Implementierung für 'print' haben. Schau Dir mal pur virtuelle Funktionen an.



  • alles klar, danke noch mal an alle 🙂



  • LukasBanana schrieb:

    Gute, Idee! Aber sind virtuelle Funktionen nicht etwas langsamer als normale?

    Da sieht man mal was diese ganzen Pseudooptimierungsaussagen anrichten können.



  • Bei einem Spiel sind virtuelle Metthoden inakzeptabel.



  • asdfasdf schrieb:

    Bei einem Spiel sind virtuelle Metthoden inakzeptabel.

    So ein Mist. Bei einem Spiel hast du ganz andere Sorgen, als ein paar virtuelle Methoden.



  • LukasBanana schrieb:

    Gute, Idee! Aber sind virtuelle Funktionen nicht etwas langsamer als normale?

    Du bist nicht echt, oder?



  • asdfasdf schrieb:

    Bei einem Spiel sind virtuelle Metthoden inakzeptabel.

    Beim Programmieren ist ein Spiel inakzeptabel.

    Jede Aussage ist gleichzeitig richtig und falsch, wenn man sie nur ausreichend verkürzt, pauschalisiert und komplett kontext- und Begründingsfrei präsentiert.

    Gruß,

    Simon2.



  • Bei einem Spiel sind virtuelle Metthoden inakzeptabel.

    lol.. das erinnert mich als an HL2 😉 wenn ich das zocke, kommt ganz selten mal eine error fenster mit der melden "Error: Pure Virtual Function call" 😉



  • Also dass virtuelle Funktionen bei Spielen inakzeptabel sein sollen würde mich aber schon sehr wundern 🙄

    Bloß ich weiß nicht, ob sich die virtuellen Funktionen den FunktionsZeiger (auf welche Funktion zu welcher Unterklasse sie nun zeigen) nur beim ersten Mal holen müssen oder bei jedem Aufruf.



  • LukasBanana schrieb:

    Bloß ich weiß nicht, ob sich die virtuellen Funktionen den FunktionsZeiger (auf welche Funktion zu welcher Unterklasse sie nun zeigen) nur beim ersten Mal holen müssen oder bei jedem Aufruf.

    Prinzipiell jedes Mal. Wie stellst Du Dir das sonst vor?


Anmelden zum Antworten