热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

解读Q_D,Q_Q指针

见qglog.h文件定义:#defineQ_D(Class)Class##Private*constdd_func()#defineQ_Q(Class)Class*c

     见 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 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 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(q_ptr); } /   
  4.     inline const QObject* q_func() const { return static_cast<const QObject *>(q_ptr); } /   
  5.     friend class QObject;   
  6.    //others  
  7. }  

  QObjectData定义如下&#xff1a;

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


三、使用的例子&#xff1a;

     在使用调色板中

[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() !&#61; 0);     
    5.     QPalette naturalPalette &#61; d->naturalWidgetPalette(d->inheritedPaletteResolveMask);  
    6.     QPalette resolvedPalette &#61; 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 &#61;&#61; palette && data.pal.resolve() &#61;&#61; palette.resolve())  
    13.         return;  
    14.     data.pal &#61; palette;  
    15.     updateSystemBackground();  
    16.     propagatePaletteChange();  
    17.     updateIsOpaque();  
    18.     q->update();  //调用QWidget::update()  
    19.     updateIsOpaque();  
    20. }  

转载于:https://www.cnblogs.com/senior-engineer/p/8065370.html


推荐阅读
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 禁止程序接收鼠标事件的工具_VNC Viewer for Mac(远程桌面工具)免费版
    VNCViewerforMac是一款运行在Mac平台上的远程桌面工具,vncviewermac版可以帮助您使用Mac的键盘和鼠标来控制远程计算机,操作简 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • Day2列表、字典、集合操作详解
    本文详细介绍了列表、字典、集合的操作方法,包括定义列表、访问列表元素、字符串操作、字典操作、集合操作、文件操作、字符编码与转码等内容。内容详实,适合初学者参考。 ... [详细]
  • 解决VS写C#项目导入MySQL数据源报错“You have a usable connection already”问题的正确方法
    本文介绍了在VS写C#项目导入MySQL数据源时出现报错“You have a usable connection already”的问题,并给出了正确的解决方法。详细描述了问题的出现情况和报错信息,并提供了解决该问题的步骤和注意事项。 ... [详细]
  • 本文详细介绍了MySQL表分区的创建、增加和删除方法,包括查看分区数据量和全库数据量的方法。欢迎大家阅读并给予点评。 ... [详细]
  • Oracle10g备份导入的方法及注意事项
    本文介绍了使用Oracle10g进行备份导入的方法及相关注意事项,同时还介绍了2019年独角兽企业重金招聘Python工程师的标准。内容包括导出exp命令、删用户、创建数据库、授权等操作,以及导入imp命令的使用。详细介绍了导入时的参数设置,如full、ignore、buffer、commit、feedback等。转载来源于https://my.oschina.net/u/1767754/blog/377593。 ... [详细]
  • 本文介绍了一些Java开发项目管理工具及其配置教程,包括团队协同工具worktil,版本管理工具GitLab,自动化构建工具Jenkins,项目管理工具Maven和Maven私服Nexus,以及Mybatis的安装和代码自动生成工具。提供了相关链接供读者参考。 ... [详细]
  • 【shell】网络处理:判断IP是否在网段、两个ip是否同网段、IP地址范围、网段包含关系
    本文介绍了使用shell脚本判断IP是否在同一网段、判断IP地址是否在某个范围内、计算IP地址范围、判断网段之间的包含关系的方法和原理。通过对IP和掩码进行与计算,可以判断两个IP是否在同一网段。同时,还提供了一段用于验证IP地址的正则表达式和判断特殊IP地址的方法。 ... [详细]
  • 本文由编程笔记小编整理,主要介绍了使用Junit和黄瓜进行自动化测试中步骤缺失的问题。文章首先介绍了使用cucumber和Junit创建Runner类的代码,然后详细说明了黄瓜功能中的步骤和Steps类的实现。本文对于需要使用Junit和黄瓜进行自动化测试的开发者具有一定的参考价值。摘要长度:187字。 ... [详细]
  • 如何在HTML中获取鼠标的当前位置
    本文介绍了在HTML中获取鼠标当前位置的三种方法,分别是相对于屏幕的位置、相对于窗口的位置以及考虑了页面滚动因素的位置。通过这些方法可以准确获取鼠标的坐标信息。 ... [详细]
  • 使用eclipse创建一个Java项目的步骤
    本文介绍了使用eclipse创建一个Java项目的步骤,包括启动eclipse、选择New Project命令、在对话框中输入项目名称等。同时还介绍了Java Settings对话框中的一些选项,以及如何修改Java程序的输出目录。 ... [详细]
  • 手把手教你使用GraphPad Prism和Excel绘制回归分析结果的森林图
    本文介绍了使用GraphPad Prism和Excel绘制回归分析结果的森林图的方法。通过展示森林图,可以更加直观地将回归分析结果可视化。GraphPad Prism是一款专门为医学专业人士设计的绘图软件,同时也兼顾统计分析的功能,操作便捷,可以帮助科研人员轻松绘制出高质量的专业图形。文章以一篇发表在JACC杂志上的研究为例,利用其中的多因素回归分析结果来绘制森林图。通过本文的指导,读者可以学会如何使用GraphPad Prism和Excel绘制回归分析结果的森林图。 ... [详细]
  • Centos7搭建ELK(Elasticsearch、Logstash、Kibana)教程及注意事项
    本文介绍了在Centos7上搭建ELK(Elasticsearch、Logstash、Kibana)的详细步骤,包括下载安装包、安装Elasticsearch、创建用户、修改配置文件等。同时提供了使用华为镜像站下载安装包的方法,并强调了保证版本一致的重要性。 ... [详细]
  • 本文介绍了在Go语言中可见性与scope的规则,包括在函数内外声明的可见性、命名规范和命名风格,以及变量声明和短变量声明的语法。同时,还介绍了变量的生命周期,包括包级别变量和局部变量的生命周期,以及变量在堆和栈上分配的规则和逃逸分析的概念。 ... [详细]
author-avatar
我和你2602883283
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有