zoukankan      html  css  js  c++  java
  • 解读 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
     
    1. class QObject  
    2. {  
    3.     Q_DECLARE_PRIVATE(QObject)  
    4. public:  
    5.     Q_INVOKABLE explicit QObject(QObject *parent=0);  
    6. protected:  
    7.     QObject(QObjectPrivate &dd, QObject *parent = 0);  
    8.     QScopedPointer<QObjectData> d_ptr;  
    9.     // others  
    10. }  
     

    展开后

    [c-sharp] view plain copy
     
    1. class QObject  
    2. {  
    3.         inline QObjectPrivate* d_func() { return reinterpret_cast(qGetPtrHelper(d_ptr)); }  
    4.     inline const QObjectPrivate* d_func() const { return reinterpret_cast(qGetPtrHelper(d_ptr)); }  
    5.     friend class QObjectPrivate;     
    6. public:  
    7.     Q_INVOKABLE explicit QObject(QObject *parent=0);  
    8. protected:  
    9.     QObject(QObjectPrivate &dd, QObject *parent = 0);  
    10.     QScopedPointer<QObjectData> d_ptr;  
    11.     // others  
    12. }  

    QObject的构造函数如下:   

    [c-sharp] view plain copy
     
    1. QObject::QObject(QObject *parent)   
    2.     : d_ptr(new QObjectPrivate)  
    3. {  
    4.   // others  
    5. }  
    6. QObject::QObject(QObjectPrivate &dd, QObject *parent)  
    7.     : d_ptr(&dd)  
    8. {  
    9.    // others  
    10. }  

    也就是QObjectData *d_ptr = new QObjectPrivate 

    显然QObjectPrivate 继承了 QObjectData  ;

    如下

    [c-sharp] view plain copy
     
    1. QObjectData {  
    2. public:  
    3.     virtual ~QObjectData() = 0;  
    4.     // others  
    5. };  
    [c-sharp] view plain copy
     
    1. class Q_CORE_EXPORT QObjectPrivate : public QObjectData  
    2. {  
    3.     Q_DECLARE_PUBLIC(QObject)  
    4. public:  
    5.     QObjectPrivate(int version = QObjectPrivateVersion);  
    6.     virtual ~QObjectPrivate();  
    7.     // others  
    8. }  

    看看QObject的一个方法

    [c-sharp] view plain copy
     
    1. QString QObject::objectName() const  
    2. {  
    3.     Q_D(const QObject);  
    4.     return d->objectName;  
    5. }  

    展开后

    [c-sharp] view plain copy
     
    1. QString QObject::objectName() const  
    2. {  
    3.     QObjectPrivate * const d = d_func()    
    4.     return d->objectName;  
    5. }  

    所以Qt 为我们把从 d_func() 获取 QObjectPrivate 指针的代码给封装起来了,之后就可以直接使用d->

    QObject的第二个构造函数使用传入的 QObjectPrivate 对象,但它是 protected 的,也就是说,你不能在外部类中使用这个构造函数。那么这个构造函数有什么用呢?我们来看一下 QWidget 的代码:

    [c-sharp] view plain copy
     
    1. class QWidget : public QObject, public QPaintDevice  
    2. {  
    3.     Q_OBJECT  
    4.     Q_DECLARE_PRIVATE(QWidget)  
    5.     // others  
    6. }  

    QWidget 是 QObject 的子类,然后看它的构造函数:

    [c-sharp] view plain copy
     
    1. QWidget::QWidget(QWidgetPrivate &dd, QWidget* parent, Qt::WindowFlags f)  
    2.     : QObject(dd, 0), QPaintDevice()  
    3. {  
    4.     Q_D(QWidget);  
    5.     QT_TRY {  
    6.         d->init(parent, f);  
    7.     } QT_CATCH(...) {  
    8.         QWidgetExceptionCleaner::cleanup(this, d_func());  
    9.         QT_RETHROW;  
    10.     }  
    11. }  
     

    显然了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
     
    1. class Q_CORE_EXPORT QObjectPrivate : public QObjectData  
    2. {  
    3.     Q_DECLARE_PUBLIC(QObject)  
    4.   public:  
    5.    //others...     
    6.     };  

    展开后:

    [cpp] view plain copy
     
    1. class Q_CORE_EXPORT QObjectPrivate : public QObjectData  
    2. {  
    3.     inline QObject* q_func() { return static_cast<QObject *>(q_ptr); } /   
    4.     inline const QObject* q_func() const { return static_cast<const QObject *>(q_ptr); } /   
    5.     friend class QObject;   
    6.    //others  
    7. }  

      QObjectData定义如下:

    [cpp] view plain copy
     
    1. QObjectData {  
    2.      public:      
    3.     QObject *q_ptr;  
    4.     //others      
    5. }  
    6. #define Q_Q(QObject) QObject * const q = q_func()   


    三、使用的例子:

         在使用调色板中

    [cpp] view plain copy
     
      1. void QWidget::setPalette(const QPalette &palette)  
      2. {  
      3.     Q_D(QWidget); //得到私有成员 QWidgetPrivate指针 d  
      4.     setAttribute(Qt::WA_SetPalette, palette.resolve() != 0);     
      5.     QPalette naturalPalette = d->naturalWidgetPalette(d->inheritedPaletteResolveMask);  
      6.     QPalette resolvedPalette = palette.resolve(naturalPalette);  
      7.     d->setPalette_helper(resolvedPalette); //调用QWidgetPrivate::setPalette_helper()  
      8. }  
      9. void QWidgetPrivate::setPalette_helper(const QPalette &palette)  
      10. {  
      11.     Q_Q(QWidget);  
      12.     if (data.pal == palette && data.pal.resolve() == palette.resolve())  
      13.         return;  
      14.     data.pal = palette;  
      15.     updateSystemBackground();  
      16.     propagatePaletteChange();  
      17.     updateIsOpaque();  
      18.     q->update();  //调用QWidget::update()  
      19.     updateIsOpaque();  
      20. }  
  • 相关阅读:
    算法学习02天nlp之TF-IDF
    kylin 密码修改
    kylin报错: failed on local exception: org.apache.hadoop.hbase.ipc.CallTimeoutException : Call id=xxxxx waitTime=xxxxx,operationTimeout = 5000 expired
    kafka 练习
    hdfs 3备份 2备份
    nlp 电商评论处理 -史诗级长文
    调用百度OCR模块进行文字识别
    简单的社交网络
    maxscript.api
    【pytorch】保存与加载模型(1.7.0官方教程)
  • 原文地址:https://www.cnblogs.com/senior-engineer/p/8065370.html
Copyright © 2011-2022 走看看