d-pointer: Welche Vorteile?
-
Hi,
ich bin eben durch Zufall auf folgenden Artikel über d-pointer aufmerksam geworden:
http://www.heise.de/developer/artikel/C-Vor-und-Nachteile-des-d-Zeiger-Idioms-Teil-1-1097781.html
Ich muss leider gestehen, da ich die Vorteile nicht so recht verstehe und hoffe das mir da jemand helfen kann.
Die Fragen die sich mir stellen:
- Bei d-pointern muss ich die Methoden sogar doppelt deklarieren (Hauptklasse und private Klasse), was ich eher als erheblichen Nachteil ansehe. Wo ist da der Vorteil?
- Dann habe ich das mit dem "Modulkonzept" nicht so recht verstanden. Was ist da gemeint worden?
- Ist das nicht sogar eher eine Art Template-Method-Pattern bzw. Proxy-Pattern? Wenn ja: Wo ist da der genaue tiefgreifende Unterschied?
Hoffe mir kann da jemand etwas Klarheit geben.

-
Nein, in die private Klassen (die IMPL-Klasse) kommen alle Daten, und je nach Geschmack auch Methoden, die du ohne Pimpl auch private gemacht hättest. Deshalb hast du auch keine Interface-Duplizierung und auch kein Proxy.
-
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?
-
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.htmPS:
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
