解读 Q_D, Q_Q 指针

42 篇文章 1 订阅

     见 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开始看 

 

展开后

 

 

QObject的构造函数如下:   

 

也就是QObjectData *d_ptr = new QObjectPrivate 

显然QObjectPrivate 继承了 QObjectData  ;

如下

 

 

看看QObject的一个方法

 

展开后

 

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

 

 

 

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

 

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

 

 

显然了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指针是在私有数据类中使用的,来获取主类指针。 

class Q_CORE_EXPORT QObjectPrivate : public QObjectData
{
    Q_DECLARE_PUBLIC(QObject)
  public:
   //others...   
    };

展开后:

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定义如下:

QObjectData {
     public:    
    QObject *q_ptr;
    //others    
}
#define Q_Q(QObject) QObject * const q = q_func() 


三、使用的例子:

     在使用调色板中

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();
}





 

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值