d-pointer: Welche Vorteile?



  • Aber ich muss doch in der Hauptklasse die von außen aufrufbare Methode implementieren und darin die Weiterleitung zur eigentlichen Implementierung in die private Klasse. Für mich klingt das nach einem Proxy oder?


  • Mod

    EasyCoder schrieb:

    Aber ich muss doch in der Hauptklasse die von außen aufrufbare Methode implementieren und darin die Weiterleitung zur eigentlichen Implementierung in die private Klasse. Für mich klingt das nach einem Proxy oder?

    Die von außen aufrufbaren Methoden sollen ja auch nicht durchgeleitet werden. Es geht nur darum die privaten Sachen zu verbergen. Die öffentlichen Methoden implementierst du ganz normal, wie du es sonst auch machen würdest. Sie dürfen(und in der Regel müssen) natürlich auch Methoden aus der privaten Klasse benutzen, aber dadurch ändert sich doch nichts.



  • Nur ein kleines Beispiel.
    Ohne Pimpl:

    class Test {
    public:
      void insert(int n);
    private:
      std::vector<int> elems_;
      bool accept(int n);
    };
    void Test::insert(int i) {
      if(accept(i)) elems_.push_back(i);
    }
    
    bool Test::accept(int i) {
      return i != 0;
    }
    

    mit pimpl:

    class Test {
    public:
      void insert(int n);
    private:
      struct Impl;
      Impl* d;
    };
    
    struct Test::Impl {
      std::vector<int> elems_;
      bool accept(int i);
    };  
    
    void Test::insert(int i) {
      if(d->accept(i)) d->elems_.push_back(i);
    }
    
    bool Test::Impl::accept(int i) {
      return i != 0;
    }
    

    Du siehst, der Code ist immer noch der selbe, bis auf den kleinen Unterschied, dass in Test der private-Teil anders ausschaut, und bei der Verwendung der vorher privatenElemente jetzt ein zusätzliches "d" steht.



  • @l'abra d'or
    Danke für das Beispiel!

    Die Frage die sich mir einfach stellt, wo soll gerade bei sowas der Vorteil sein? Ich seh da (leider) bisher keinen praktischen oder theoretischen. 😞

    Einfach die Frage: Warum benutzen?



  • EasyCoder schrieb:

    Einfach die Frage: Warum benutzen?

    Steht in dem Artikel genau beschrieben.



  • @Shade Of Mine
    Wie schon gesagt habe ich es nicht genau verstanden, drum die Frage ob es mir jemand verdeutlichen könnte und nicht einfach sagt: "Ist so!".

    Sorry, bin keiner der 10 Jahre beruflich C++ programmiert. Darum frage ich ja!



  • Wenn Du als Beispiel eine Library (statisch oder dynamisch) erstellst und die Implementation verstecken willst oder haufenweise private Member hast, die im Header nicht auftauchen sollen oder dürfen wegen Implementationsdetails und ähnlichem. Oder auch nur um Vervollständigungsmechanismen zu entlasten.
    Gibt viele Möglichkeiten.
    Oder um eine Implementation schnell austauschen zu können bei Bedarf.

    class IMyInterface
    {
    public:
       virtual void foobar() = 0;
    };
    
    class MyInterfaceImpl : public IMyInterface
    {
    public:
       virtual void foobar();
    };
    
    class MyInterface
    {
    public:
       MyInterface( IMyInterface* p )
       {
          m_pImpl = p;
       }
    
       virtual void foobar()
       {
          m_pImpl->foobar();
       }
    private:
       IMyInterface* m_pImpl;
    };
    

    So als kleines Beispiel. So kann der User der Library seine eigene Implementation einbauen.

    edits: was korrigiert :p nicht mein tag heute :S
    rya.



  • Primärvorteil: Kompilierungszeit verkürzen. Einfach durch Entfernung von Abhängigkeiten im Header.
    Das obige Beispiel hätte einen "#include <vector>" direkt im Header gebraucht. Jede Übersetzungseinheit, die den test.h-Header einbindet, bindet automatisch std::vector ein. Das führt zu erhöhter Kompilierzeit.
    Durch das Pimpl braucht es den #include erst in der Dateie, in der Test::Impl definiert wird (üblicherweise test.cpp, wo also auch Methoden von Test definiert werden). Damit beschleunigt sich der Kompiliervorgang aller Einheiten, die test.h einbinden. Vor allem wenn sich etwas in Test::Impl ändert, muss nicht alles neu kompiliert werden (Für mal ohne Pimpl ein neues Datenelement hinzu, und schau wie alles neu kompiliert werden muss).

    Sekundärvorteil: Bei Änderungen der Daten (Hinzufügen, Entfernen, umsortieren von Datenelementen) ändert sich die Binärschnittstelle (ABI) nicht. Man kann also eine Lib aktualisieren, ohne alle verwendenene Applikationen neu übersetzen zu müssen.

    Herb Sutter hat in "Exceptional C++" einiges darüber geschrieben.



  • @Scorcher24
    Vielen Dank! Das war mal ein sehr sinnvolles Beispiel das mir den Nutzen mal richtig verdeutlicht hat. 🙂

    Schade, das sowas nicht von dem Mod kommt, sondern nur sowas nutzloses "Steht doch da" und man den Wald vor lauter Bäumen nicht sieht.

    Drum: 👍 Scorcher24 👍



  • EasyCoder schrieb:

    Wie schon gesagt habe ich es nicht genau verstanden, drum die Frage ob es mir jemand verdeutlichen könnte und nicht einfach sagt: "Ist so!".

    Men reduziert damit Abhängigkeiten.

    Siehe ähnliche Artikel:
    http://www.gotw.ca/gotw/024.htm
    http://www.gotw.ca/publications/mill05.htm
    http://www.gotw.ca/publications/mill04.htm

    PS:
    mit steht da, meine ich zB dieses Beispiel:

    So hat Nokias "Qt Development Frameworks"-Abteilung (vormals Trolltech) bei der Klassenbibliothek "Qt 4" bei mindestens zwei Gelegenheiten tiefgreifende Änderungen am Widget-Rendering durchgeführt, ohne dass die Qt 4 benutzenden Programme hierfür auch nur neu gebunden hätten werden müssen.



  • Dickes Danke natürlich auch an l'abra d'or 🙂


Anmelden zum Antworten