Problem mit PImpl-Idiom



  • Hi.

    Ich hab ein Problem mit dem PImpl-Idiom und den übergebenen Daten.
    Ich habe momentan 2 Klassen:

    Window und Driver. Driver braucht unter Win32 das handle auf das Fenster von Window. Da ich das Interface der API aber X-Platform halten möchte, kommt natürlich eine Rückgabe-Funktion ala HWND getWindowHandle() nicht in Frage.
    Wenn ich hier nur void* zurückgebe, dann ist das nicht mehr typensicher.
    Wäre es evtl gut hier ein Template zu verwenden? Aber das führt oft zu ungewollten Rekursionen.
    Zum Verständnis, der Code ist gekürzt auf das wesentliche:

    class CRealWindow
    {
    public:
      CRealWindow() : m_hwnd(NULL) {}
      ~CRealWindow(){ destroyWindow(); }
      void createWindow(const WindowSettings& settings) { /* gekürzt */ }
    
    private:
      HWND m_hwnd 
    };
    
    class CWindow
    {
    public:
      CWindow(){ m_pimpl = new CRealWindow(); }
      ~CWindow() { delete m_pimpl; }
      void createWindow(const WindowSettings& settings) { m_pimpl->createWindow(settings); }
    private:
      CRealWindow *m_pimpl;
    };
    
    class CDriver
    {
    public:
       explicit CDriver( CWindow* window );
    
    };
    
    Class CRealDriver
    {
      // usw
    };
    

    Frage ist also: Wie kriege ich das HWND in die Klasse Driver über die Proxy-Klasse ohne Platformspezifisch zu werden und typensicher zu bleiben? Oder muss ich hier einen Tod der beiden sterben? 🙂
    lg



  • Warum braucht der Driver das Handle? der Driver braucht höchtens einen Pointer auf ein CWindow. Was da drin dann genau passiert ist wurscht.

    Allerdings ist CWindow auch nicht plattformunabhängig, weils auf CRealwindow zugreift, was eben Windows-Spezifisch ist.



  • Dass das intern nicht X-Platform ist, ist klar, aber nach aussen schon.. über #ifdef WIN32 können ja die real-klassen entsprechend ausgetauscht werden.
    Und doch, ich brauch das Handle auf HWND... sonst kann ich DirectX nicht starten.
    Ich habs hier gepostet, weil das ja eher ein Problem meiner Struktur ist, als eines von DirectX.
    lg



  • #ifdef WIN32
        typedef HWND HWindow;
    #else
        typedef int HWindow;
    #endif
    
    class CWindow
    {
      ...
      HWindow getHandle() const { return m_impl->getHandle(); }
    };
    


  • Registrierter Troll schrieb:

    #ifdef WIN32
        typedef HWND HWindow;
    #else
        typedef int HWindow;
    #endif
    
    class CWindow
    {
      ...
      HWindow getHandle() const { return m_impl->getHandle(); }
    };
    

    So einfach :D.
    Schon eingebaut.
    Stoße jetzt aber auf ein anderes problem.. 😡

    Folgende Klassen:

    IVideoDriver: Basis-Klasse die alle Methoden als pure virtual vorgibt, die ein "VideoDriver" haben muss, wie RenderQuad, CreateTexture etc.

    VideoDriver: Wählt aus den verfügbaren Klassen die IVideoDriver implementieren die beste aus und allokiert m_impl auf diese mittels eines switches oder nimmt einen an den constructor übergebenen zeiger auf eine klasse die IVideoDriver implementiert.

    RealVideoDriverDX9: Implementiert IVideoDriver für DirectX9. Im Destruktor der Klasse wird Direct3D9 freigegeben mit Release().

    Lösche ich jetzt IVideoDriver* m_impl im Destruktor von VideoDriver bevor ich die Direct3D9-Interfaces freigegeben habe, crasht die Anwendung beim beenden beim löschen von m_impl mit der Meldung "_BLOCK_TYPE_IS_VALID(pHead->nBlockUse)".
    Weiss jemand warum? Wie ist denn die vorgehensweise vom Compiler beim löschen? Kann ich das kontrollieren irgendwie? Ich habs jetzt umgangen, indem ich zu IVideoDriver eine "cleanup"-Funktion hinzugefügt habe. Damit werden die Interfaces aus Dx9 vorher freigegeben und dann erst der m_impl-zeiger gelöscht.
    Aber das soll ja eigentlich der Deconstructor tun.
    lg

    ps.: Ja, ich will ein kleines Spiel machen, schlage mich aber derzeit noch mit C++ rum.... daher finde ich passt es doch in dieses Forum.


Log in to reply