The English version is available at: http://xizhizhu./2010/11/beauty-of-qt-1-d-pointer-private.html
相信不少剛開始閱讀Qt源代碼的朋友在看到其中的Private類和諸如Q_D、Q_Q等宏時(shí)都會(huì)思考,為什么Qt要用這樣一個(gè)設(shè)計(jì)模式呢?這樣一段增加了不少復(fù)雜度的代碼,到底有多大的好處呢?簡(jiǎn)單的說,這樣的好處在于保證代碼的二進(jìn)制兼容性。
什么是二進(jìn)制兼容性?大名鼎鼎的KDE項(xiàng)目是這樣介紹的:一個(gè)庫是二進(jìn)制兼容的,如果一個(gè)程序和某個(gè)庫的某個(gè)版本動(dòng)態(tài)鏈接,并且不需要重新編譯,即可在安裝有該庫較新版本的環(huán)境中運(yùn)行。為什么要保證二進(jìn)制兼容性?如果不能保證庫的二進(jìn)制兼容性,就意味著每次發(fā)布新版本時(shí),依賴該庫的所有程序都必須重新編譯才能正常運(yùn)行。顯然,這對(duì)于像Qt這樣被廣泛采用的庫而言是完全不可接受的。關(guān)于二進(jìn)制兼容性的更多信息,感興趣的朋友可以參考下KDE TechBase上的這篇文章,這里就不羅嗦了,僅僅和大家分享下具體的使用。
如果不使用D指針,那我們可能會(huì)有如下的一個(gè)類聲明:
class MyClass
{ public: MyClass(); ~MyClass(); private: int myVar; }; class MyClass { public: MyClass(); ~MyClass(); private: int myVar; }; 顯然,這里的私有成員myVar是保證代碼二進(jìn)制兼容性的大敵,所以我們需要使用D指針,改寫這個(gè)類:
class MyClassPrivate;
class MyClass { public: MyClass(); ~MyClass(); private: MyClassPrivate * const d_ptr; Q_DECLARE_PRIVATE(MyClass); }; class MyClassPrivate; class MyClass { public: MyClass(); ~MyClass(); private: MyClassPrivate * const d_ptr; Q_DECLARE_PRIVATE(MyClass); }; 這里,我們定義了一個(gè)指針d_ptr指向私有實(shí)現(xiàn)類,然后用Q_DECLARE_PRIVATE宏來定義一些輔助函數(shù)和聲明友元類:
#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; #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; 然后這個(gè)私有類的實(shí)現(xiàn)如下所示:
class MyClassPrivate
{ public: MyClassPrivate(MyClass *parent); private: MyClass * const q_ptr; Q_DECLARE_PUBLIC(MyClass); int myVar; }; class MyClassPrivate { public: MyClassPrivate(MyClass *parent); private: MyClass * const q_ptr; Q_DECLARE_PUBLIC(MyClass); int myVar; }; 這里的q_ptr指針就是指向公開的接口了,然后Q_DECLARE_PUBLIC宏則定義了輔助函數(shù)并聲明了友元類:
#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; #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兩個(gè)宏來進(jìn)一步簡(jiǎn)化訪問:
#define Q_D(Class) Class##Private * const d = d_func()
#define Q_Q(Class) Class * const q = q_func() #define Q_D(Class) Class##Private * const d = d_func() #define Q_Q(Class) Class * const q = q_func() 這就是Qt中D指針/私有實(shí)現(xiàn)的最基本使用方法。最后用一個(gè)比較完整的例子作為結(jié)尾;)
// 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(); } 本文來自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/zhu_xz/archive/2010/11/25/6035861.aspx
|
|