日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

解读 Q_D, Q_Q 指针

發布時間:2025/5/22 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 解读 Q_D, Q_Q 指针 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

? ? ?見 qglog.h文件定義:???

??? #define Q_D(Class) Class##Private * const d = d_func()
??? #define Q_Q(Class) Class * const q = q_func()

??d指針是在主類中使用的,來獲取私有子類成員指針

??q指針是在私有數據類中使用的,來獲取主類對象指針

D-指針?
?? 私有成員總是不可見的,Qt中私有成員不僅僅是簡單封裝一下,將訪問權限改為private,它將所有私有數據封裝在私有類里(命名就是 classname##private), 這樣一來連用戶都不知道他到底封裝了什么,程序中只有這個私有類成員指針,這個指針就是D-指針。

從QObject開始看?

?

[c-sharp]?view plain?copy
  • class?QObject??
  • {??
  • ????Q_DECLARE_PRIVATE(QObject)??
  • public:??
  • ????Q_INVOKABLE?explicit?QObject(QObject?*parent=0);??
  • protected:??
  • ????QObject(QObjectPrivate?&dd,?QObject?*parent?=?0);??
  • ????QScopedPointer<QObjectData>?d_ptr;??
  • ????//?others??
  • }??
  • ?

    ?

    ?

    ?

    展開后

    ?

    [c-sharp]?view plain?copy
  • class?QObject??
  • {??
  • ????????inline?QObjectPrivate*?d_func()?{?return?reinterpret_cast(qGetPtrHelper(d_ptr));?}??
  • ????inline?const?QObjectPrivate*?d_func()?const?{?return?reinterpret_cast(qGetPtrHelper(d_ptr));?}??
  • ????friend?class?QObjectPrivate;?????
  • public:??
  • ????Q_INVOKABLE?explicit?QObject(QObject?*parent=0);??
  • protected:??
  • ????QObject(QObjectPrivate?&dd,?QObject?*parent?=?0);??
  • ????QScopedPointer<QObjectData>?d_ptr;??
  • ????//?others??
  • }??
  • ?

    ?

    ?

    ?

    ?

    QObject的構造函數如下:???

    ?

    [c-sharp]?view plain?copy
  • QObject::QObject(QObject?*parent)???
  • ????:?d_ptr(new?QObjectPrivate)??
  • {??
  • ??//?others??
  • }??
  • QObject::QObject(QObjectPrivate?&dd,?QObject?*parent)??
  • ????:?d_ptr(&dd)??
  • {??
  • ???//?others??
  • }??
  • ?

    ?

    ?

    ?

    也就是QObjectData *d_ptr = new QObjectPrivate?

    顯然QObjectPrivate 繼承了 QObjectData? ;

    如下

    ?

    [c-sharp]?view plain?copy
  • QObjectData?{??
  • public:??
  • ????virtual?~QObjectData()?=?0;??
  • ????//?others??
  • };??
  • ?

    ?

    ?

    ?

    ?

    [c-sharp]?view plain?copy
  • class?Q_CORE_EXPORT?QObjectPrivate?:?public?QObjectData??
  • {??
  • ????Q_DECLARE_PUBLIC(QObject)??
  • public:??
  • ????QObjectPrivate(int?version?=?QObjectPrivateVersion);??
  • ????virtual?~QObjectPrivate();??
  • ????//?others??
  • }??
  • ?

    ?

    ?

    ?

    看看QObject的一個方法

    ?

    ?

    [c-sharp]?view plain?copy
  • QString?QObject::objectName()?const??
  • {??
  • ????Q_D(const?QObject);??
  • ????return?d->objectName;??
  • }??
  • ?

    ?

    ?

    展開后

    ?

    [c-sharp]?view plain?copy
  • QString?QObject::objectName()?const??
  • {??
  • ????QObjectPrivate?*?const?d?=?d_func()????
  • ????return?d->objectName;??
  • }??
  • ?

    ?

    ?

    所以Qt 為我們把從 d_func() 獲取 QObjectPrivate 指針的代碼給封裝起來了,之后就可以直接使用d->

    ?

    ?

    ?

    QObject的第二個構造函數使用傳入的 QObjectPrivate 對象,但它是 protected 的,也就是說,你不能在外部類中使用這個構造函數。那么這個構造函數有什么用呢?我們來看一下 QWidget 的代碼:

    ?

    [c-sharp]?view plain?copy
  • class?QWidget?:?public?QObject,?public?QPaintDevice??
  • {??
  • ????Q_OBJECT??
  • ????Q_DECLARE_PRIVATE(QWidget)??
  • ????//?others??
  • }??
  • ?

    ?

    ?

    ?

    QWidget 是 QObject 的子類,然后看它的構造函數:

    ?

    [c-sharp]?view plain?copy
  • QWidget::QWidget(QWidgetPrivate?&dd,?QWidget*?parent,?Qt::WindowFlags?f)??
  • ????:?QObject(dd,?0),?QPaintDevice()??
  • {??
  • ????Q_D(QWidget);??
  • ????QT_TRY?{??
  • ????????d->init(parent,?f);??
  • ????}?QT_CATCH(...)?{??
  • ????????QWidgetExceptionCleaner::cleanup(this,?d_func());??
  • ????????QT_RETHROW;??
  • ????}??
  • }??
  • ?

    ?

    ?

    ?

    ?

    顯然了QWidgetPrivate 繼承了QObjectPrivate

    于是我們已經明白,為什么 QWidget 中找不到 d_ptr 了,因為所有的 d_ptr 都已經在父類 QObject 中定義好了!嘗試展開一下 Q_DECLARE_PRIVATE 宏,你就能夠發現,它實際上把父類的 QObjectPrivate 指針偷偷地轉換成了 QWidgetPrivate 的指針。

    ?

    因此有如下結論:?

    1、在基類中定義一個protected權限的基類私有類d_ptr指針;

    2、在每個派生類中用本類私有類初始化d_ptr(該私有類需要繼承基類私有類),并定義d_func(),獲取基類d_ptr,這個d_func()是由?????Q_DECLARE_PRIVATE展開得來的?,并將其轉換為當前私有類指針;


    3、在函數中使用Q_D,這樣就可以使用d了;
    4、在私有數據繼承體系中,不要忘記將析構函數定義為虛函數,基類析構函數中釋放d_ptr,以防內存泄露!!!

    ============================================================

    Q-指針?
    ?? q指針是在私有數據類中使用的,來獲取主類指針。?

    [cpp]?view plain?copy
  • class?Q_CORE_EXPORT?QObjectPrivate?:?public?QObjectData??
  • {??
  • ????Q_DECLARE_PUBLIC(QObject)??
  • ??public:??
  • ???//others...?????
  • ????};??
  • 展開后:

    [cpp]?view plain?copy
  • class?Q_CORE_EXPORT?QObjectPrivate?:?public?QObjectData??
  • {??
  • ????inline?QObject*?q_func()?{?return?static_cast<QObject?*>(q_ptr);?}?/???
  • ????inline?const?QObject*?q_func()?const?{?return?static_cast<const?QObject?*>(q_ptr);?}?/???
  • ????friend?class?QObject;???
  • ???//others??
  • }??
  • ? QObjectData定義如下:

    [cpp]?view plain?copy
  • QObjectData?{??
  • ?????public:??????
  • ????QObject?*q_ptr;??
  • ????//others??????
  • }??
  • #define?Q_Q(QObject)?QObject?*?const?q?=?q_func()???

  • 三、使用的例子:

    ???? 在使用調色板中

    [cpp]?view plain?copy
  • void?QWidget::setPalette(const?QPalette?&palette)??
  • {??
  • ????Q_D(QWidget);?//得到私有成員?QWidgetPrivate指針?d??
  • ????setAttribute(Qt::WA_SetPalette,?palette.resolve()?!=?0);?????
  • ????QPalette?naturalPalette?=?d->naturalWidgetPalette(d->inheritedPaletteResolveMask);??
  • ????QPalette?resolvedPalette?=?palette.resolve(naturalPalette);??
  • ????d->setPalette_helper(resolvedPalette);?//調用QWidgetPrivate::setPalette_helper()??
  • }??
  • void?QWidgetPrivate::setPalette_helper(const?QPalette?&palette)??
  • {??
  • ????Q_Q(QWidget);??
  • ????if?(data.pal?==?palette?&&?data.pal.resolve()?==?palette.resolve())??
  • ????????return;??
  • ????data.pal?=?palette;??
  • ????updateSystemBackground();??
  • ????propagatePaletteChange();??
  • ????updateIsOpaque();??
  • ????q->update();??//調用QWidget::update()??
  • ????updateIsOpaque();??
  • }??
  • 轉載于:https://www.cnblogs.com/senior-engineer/p/8065370.html

    總結

    以上是生活随笔為你收集整理的解读 Q_D, Q_Q 指针的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。