Q_DECLARE_PRIVATE與Q_DECLARE_PUBLIC
來源 https://blog.csdn.net/liulihuo_gyh/article/details/80081069
參考 https://blog.csdn.net/seanyxie/article/details/6120036
參考 https://blog.csdn.net/Andy_93/article/details/77587797
參考 https://blog.csdn.net/qq_39937902/article/details/79738160
這兩個宏在Qt的源碼中隨處可見,重要性不言而喻。在 部落格的 Inside Qt Series 系列文章中,他用了3篇文章來講這個問題。
因為 QObject 本身比較復雜,這兩個宏和一個復雜的東西攪和到一塊,還真是不好理解。不過幸好,這個兩個宏和QObject 沒有必然的聯系。故接下來,忘記 QObject,看一個普通的C++的類。
例子
類 QtServiceController 定義:
class QtServiceController { Q_DECLARE_PRIVATE(QtServiceController) public: QtServiceController(const QString &name); //省略其他 private: QtServiceControllerPrivate *d_ptr; };
宏定義
宏定義在 QtGlobal(即qglobal.h)頭文件中:
#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_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;
這兩個宏在這看起來真蠻繞的,因為這個例子太簡單了,兩個宏的威力發揮不出來。反正核心就是:
-
在 QtServiceController 中通過 d_func() 可以獲得 QtServiceControllerPrivate 的指針 d_ptr
-
在 QtServiceControllerPrivate 中通過 q_func() 可以獲得 QtServiceController 的指針 q_ptr
Q_D 與 Q_Q
這是另兩個Qt源碼中隨處可見的宏,那么它們有什么用呢?
#define Q_D(Class) Class##Private * const d = d_func()
#define Q_Q(Class) Class * const q = q_func()
兩個宏展開后分別是對 d_func 和 q_func 兩個函數的調用,返回值分別賦值給 d 和 q 兩個指針變量。
於是:
-
在 QtServiceController 中的成員函數中,我們只需要添加 Q_D(QtServiceController) 宏,在該函數內就可以直接用 d 來指代 d_ptr
-
在 QtServiceControllerPrivate 中的成員函數中,我們只需要添加 Q_Q(QtServiceController)宏,在該函數內就可以直接用 q 來指代 q_ptr
d_ptr與q_ptr
繞這么大圈,為什么不直接用 d_ptr 與 q_ptr 呢。在,在我們的例子中,確實可以直接用,而且會更直接更簡單。官方這么用了,或許是為了和其他類保持一致吧。
但在其他情況下,這么做顯然是有意義的,因為 d_ptr 與 d,q_ptr 與 q 的類型並不一致(比如QObject系列)。這也是為何宏展開后有cast的原因
Q_DISABLE_COPY
QObject 中沒有提供一個拷貝構造函數和賦值操作符給外界使用,其實拷貝構造和賦值的操作都是已經聲明了的,但是它們被使用了Q_DISABLE_COPY() 宏放在了private區域。因此所有繼承自QObject的類都使用這個宏聲明了他們的拷貝構造函數和賦值操作符為私有。
為什么要這樣做?
我們都知道Qt對標准C++增加了一些功能:signals, slots, object properties, events, event filters, string translation, timers,object trees, guarded pointers, dynamic cast.
新加入的這些功能就要求我們把每一個QObject的對象看做是唯一(identities)的。唯一的意思就是不能通過拷貝或者賦值操作
制作出一個一模一樣的復制體。
試想如果我們有一個QPushButton對象btnSubmit,如果我們可以復制出一個和btnSubmint完全一樣的button對象,那么新的button對象的名字應該是什么?如果也叫btnSubmit,當我們給其中的btnSubmit接收事件或發出信號時,系統如何區分把事件由哪個button對象接收,或者哪個對象發送了信號?
我們知道在各種容器中能以value方式存放的類型,必須有默認的構造函數,拷貝構造函數和賦值操作。由於QObject及所有繼承自它的子類都沒有提供拷貝構造和賦值操作,當我們使用QList<QObject>時,編譯器就會報錯。如果我們要在容器中存儲這中類型的對象,我們就要使用它們的指針。如QList<QObject *>
========== End