Q_DECLARE_PRIVATE與Q_DECLARE_PUBLIC


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

Q_DECLARE_PRIVATE與Q_DECLARE_PUBLIC

這兩個宏在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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM