d-pointer was beachten bei kopieren oder ableiten



  • Ich verwende inzwischen regelmäßig das Konzept des d-pointers (siehe z.B. http://www.heise.de/developer/artikel/C-Vor-und-Nachteile-des-d-Zeiger-Idioms-Teil-1-1097781.html)

    Jetzt möchte ich eine solche Klasse ableiten und kenne dadurch die private d-Pointer Klasse nicht mehr. Zusätzlich habe ich mir gedacht, das man zum kopieren explizite Copy Contructoren benötigt und mich gefragt ob man dabei etwas beachten müsste. Dies sollten Probleme sein zu denen es bekannte Lösungen gibt, ich wüsste nun gerne wie die aussehen, oder wo ich diese nachlesen



  • pospiech schrieb:

    Jetzt möchte ich eine solche Klasse ableiten und kenne dadurch die private d-Pointer Klasse nicht mehr.

    Das ist doch auch gut so.

    pospiech schrieb:

    Zusätzlich habe ich mir gedacht, das man zum kopieren explizite Copy Contructoren benötigt und mich gefragt ob man dabei etwas beachten müsste. Dies sollten Probleme sein zu denen es bekannte Lösungen gibt, ich wüsste nun gerne wie die aussehen, oder wo ich diese nachlesen

    Steht doch in dem von dir velinkten Artikel drin. Sogar mit move ctor. Oder was genau ist da nihct klar?



  • pospiech schrieb:

    Ich verwende inzwischen regelmäßig das Konzept des d-pointers (siehe z.B. http://www.heise.de/developer/artikel/C-Vor-und-Nachteile-des-d-Zeiger-Idioms-Teil-1-1097781.html)

    Jetzt möchte ich eine solche Klasse ableiten

    Welche? Class oder Class::Private?

    pospiech schrieb:

    und kenne dadurch die private d-Pointer Klasse nicht mehr. Zusätzlich habe ich mir gedacht, das man zum kopieren explizite Copy Contructoren benötigt und mich gefragt ob man dabei etwas beachten müsste. Dies sollten Probleme sein zu denen es bekannte Lösungen gibt, ich wüsste nun gerne wie die aussehen, oder wo ich diese nachlesen

    Ein Vorteil bei diesem Ansatz ist es, dass man Implementierungsdetails verstecken kann.

    Ich habe es in einer eigenen Bibliothek benutzt und das sah in etwa so aus:

    include/camera.hpp (öffentlicher Header der Lib)

    // Wird innerhalb der Bibliothek als abstrakte Basisklasse definiert
    // und abgeleitet
    class abstract_camera;
    
    class camera
    {
      abstract_camera* ptr;
      friend class abstract_camera;
      explicit camera(abstract_camera* p) : ptr(p) {}
    
    public:
      camera() : ptr(0) {}
      bool valid() const {return ptr;}
      ~camera();
      void swap(camera & that) { std::swap(this->ptr,that.ptr); }
      camera(camera const& x);
      camera& operator=(camera temp) { swap(temp); return *this; }
    
      point2d projection(point3d const&) const;
    };
    
    inline void swap(camera & a, camera & b) { a.swap(b); }
    

    libsrc/abstract_camera.hpp (privater Header)

    #include "camera.hpp"
    
    class abstract_camera
    {
    public:
      virtual ~abstract_camera() {}
      virtual abstract_camera* clone() const = 0;
    
      virtual point2d projection(point3d const&) const = 0;
    
      static camera wrap(abstract_camera* ptr) { return camera(ptr); }
    };
    

    libsrc/camera.cpp (Implementierung)

    #include "camera.hpp"
    #include "abstract_camera.hpp"
    
    camera::camera(camera const& x)
    : ptr(x.ptr ? x.ptr->clone() : 0)
    {}
    
    camera::~camera()
    { delete ptr; }
    
    point2d camera::projection(point3d const& x) const
    { return ptr->projection(x); }
    

    Der Haken ist aber, dass man die Schnittstelle quasi 2mal hinschreiben muss. Einmal in der abstrakten Basisklasse und einmal in der Wrapper-Klasse mit den Weiterleitungen (siehe Implementierung von camera::projection).

    Das mit der "Verdopplung der Schnittstelle" könnte man reduzieren, indem man die abstrakte Basisklasse öffentlich macht und direkten Zugriff erlaubt:

    class camera
    {
      abstract_camera* ptr;
    public:
      ...
      abstract_camera const* operator->() const {return ptr;}
      abstract_camera      * operator->()       {return ptr;}
    };
    
    ...
    
    void foo(camera const& x)
    {
      point3d xyz = ...;
      point2d uv = x->projection(xyz);
    }
    

    Aber dann kann man "camera" auch generisch machen und "clone_ptr" nennen:

    template<class T>
    class clone_ptr
    {
      ...
    
      clone_ptr(clone_ptr const& x)
      : ptr(x.ptr ? x.ptr->clone() : 0)
      {}
    
      ~clone_ptr()
      { delete ptr; }
    
      T const* operator->() const {return ptr;}
      T      * operator->()       {return ptr;}
    
      ...
    };
    

    ...welcher im C++0x Modus noch Move-Operationen bekommen könnte. Jepp, das gefällt mir eigentlich jetzt am besten so mit clone_ptr.


Anmelden zum Antworten