版權聲明:本文爲博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連接和本聲明。
本文連接:https://blog.csdn.net/zhu_xz/article/details/6035861
The English version is available at: http://xizhizhu.blogspot.com/2010/11/beauty-of-qt-1-d-pointer-private.htmlhtml
相信很多剛開始閱讀Qt源代碼的朋友在看到其中的Private類和諸如Q_D、Q_Q等宏時都會思考,爲何Qt要用這樣一個設計模式呢?這樣一段增長了很多複雜度的代碼,到底有多大的好處呢?簡單的說,這樣的好處在於保證代碼的二進制兼容性。設計模式
什麼是二進制兼容性?大名鼎鼎的KDE項目是這樣介紹的:一個庫是二進制兼容的,若是一個程序和某個庫的某個版本動態連接,而且不須要從新編譯,便可在安裝有該庫較新版本的環境中運行。爲何要保證二進制兼容性?若是不能保證庫的二進制兼容性,就意味着每次發佈新版本時,依賴該庫的全部程序都必須從新編譯才能正常運行。顯然,這對於像Qt這樣被普遍採用的庫而言是徹底不可接受的。關於二進制兼容性的更多信息,感興趣的朋友能夠參考下KDE TechBase上的這篇文章,這裏就不羅嗦了,僅僅和你們分享下具體的使用。函數
若是不使用D指針,那咱們可能會有以下的一個類聲明: this
class MyClass { public: MyClass(); ~MyClass(); private: int myVar; };
顯然,這裏的私有成員myVar是保證代碼二進制兼容性的大敵,因此咱們須要使用D指針,改寫這個類:spa
class MyClassPrivate; class MyClass { public: MyClass(); ~MyClass(); private: MyClassPrivate * const d_ptr; Q_DECLARE_PRIVATE(MyClass); };
這裏,咱們定義了一個指針d_ptr指向私有實現類,而後用Q_DECLARE_PRIVATE宏來定義一些輔助函數和聲明友元類:.net
#define Q_DECLARE_PRIVATE(Class) / inline Class##Private* d_func() { return reinterpret_cast<Class##Private *>(qGetPtrHelper(d_ptr)); } / inline const Class##Private* d_func() const { return reinterpret_cast<const Class##Private *>(qGetPtrHelper(d_ptr)); } / friend class Class##Private;
而後這個私有類的實現以下所示:設計
class MyClassPrivate { public: MyClassPrivate(MyClass *parent); private: MyClass * const q_ptr; Q_DECLARE_PUBLIC(MyClass); int myVar; };
這裏的q_ptr指針就是指向公開的接口了,而後Q_DECLARE_PUBLIC宏則定義了輔助函數並聲明瞭友元類:指針
#define Q_DECLARE_PUBLIC(Class) / inline Class* q_func() { return static_cast<Class *>(q_ptr); } / inline const Class* q_func() const { return static_cast<const Class *>(q_ptr); } / friend class Class;
而咱們還能夠用Q_D和Q_Q兩個宏來進一步簡化訪問:code
#define Q_D(Class) Class##Private * const d = d_func() #define Q_Q(Class) Class * const q = q_func()
這就是Qt中D指針/私有實現的最基本使用方法。最後用一個比較完整的例子做爲結尾;)htm
// myclass.h #ifndef MYCLASS_H #define MYCLASS_H #include <QtCore/QObject> class MyClassPrivate; class MyClass: public QObject { Q_OBJECT public: MyClass(QObject *parent = 0); virtual ~MyClass(); void dummyFunc(); signal: void dummySignal(); private: MyClassPrivate * const d_ptr; Q_DECLARE_PRIVATE(MyClass); Q_DISABLE_COPY(MyClass); }; #endif // MYCLASS_H // myclass.cpp #include "myclass.h" class MyClassPrivate { public: MyClassPrivate(MyClass *parent) : q_ptr(parent) { } void foobar() { Q_Q(MyClass); emit q->dummySignal(); } private: MyClass * const q_ptr; Q_DECLARE_PUBLIC(MyClass); }; MyClass::MyClass(QObject *parent) : QObject(parent) , d_ptr(new MyClassPrivate(this)) { } MyClass::~MyClass() { Q_D(MyClass); delete d; } void MyClass::dummyFunc() { Q_D(MyClass); d->foobar(); }