解读 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开始看
展开后
- 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的构造函数如下:
- 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 ;
如下
- QObjectData {
- public:
- virtual ~QObjectData() = 0;
- // others
- };
- class Q_CORE_EXPORT QObjectPrivate : public QObjectData
- {
- Q_DECLARE_PUBLIC(QObject)
- public:
- QObjectPrivate(int version = QObjectPrivateVersion);
- virtual ~QObjectPrivate();
- // others
- }
看看QObject的一个方法
- QString QObject::objectName() const
- {
- Q_D(const QObject);
- return d->objectName;
- }
展开后
- QString QObject::objectName() const
- {
- QObjectPrivate * const d = d_func()
- return d->objectName;
- }
所以Qt 为我们把从 d_func() 获取 QObjectPrivate 指针的代码给封装起来了,之后就可以直接使用d->
QObject的第二个构造函数使用传入的 QObjectPrivate 对象,但它是 protected 的,也就是说,你不能在外部类中使用这个构造函数。那么这个构造函数有什么用呢?我们来看一下 QWidget 的代码:
- class QWidget : public QObject, public QPaintDevice
- {
- Q_OBJECT
- Q_DECLARE_PRIVATE(QWidget)
- // others
- }
QWidget 是 QObject 的子类,然后看它的构造函数:
- 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指针是在私有数据类中使用的,来获取主类指针。
- 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();
- }
解读 Q_D, Q_Q 指针的更多相关文章
- [C/C++]如何解读返回函数指针的函数声明
今天在看<深入理解C++11>的时候,看到一段有意思的代码: int (*(*pf())())() { return nullptr; } 我立刻就懵了——从来没有见过这样的函数声明.那么 ...
- Qt信息隐藏(Q_D/Q_Q)介绍——从二进制兼容讲起
http://www.cnblogs.com/SkylineSoft/articles/2046404.html
- C++指针的概念解读
C++指针的概念解读 超详细 指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址.要搞清一个指针需要搞清指针的四方面的内容:指针的类型,指针所指向的类型,指针的值或者叫指针所指向的内存区 ...
- Netty之缓冲区ByteBuf解读(二)
上篇介绍了 ByteBuf 的简单读写操作以及读写指针的基本介绍,本文继续对 ByteBuf 的基本操作进行解读. 读写指针回滚 这里的 demo 例子还是使用上节使用的. ByteBuf buf = ...
- C/C++中的 if(指针变量) 和 if(!指针变量)
目录 if(指针变量) 代码演示 if(指针变量) 解读代码 if(!指针变量) 解读代码 总结 替代方案.推荐写法!!!!! if(指针变量) 当把一个指针作为条件表达式时,所要判断的条件实际上就是 ...
- Qt之二进制兼容
一.回顾 使用qt2年多了,但是还是觉得很陌生,总是会被qt搞的很紧张,有时候当我自信满满的打开帮助文档,搜索某个已知的类时,由于笔误敲错了一个字母而出现了另外一个类,不过奇怪的是还真有这么一个类,哎 ...
- 30.C++复习篇
本章学习内容: 1.const 2.指针const 3.inline内联函数 4.函数重载 5.extern “C” 6.new/delete声明与释放 7.namespace命名空间 8.C++中的 ...
- Qt中的Q_D宏和d指针
_ZTS7QObject 一.Q_D的在文件中的提法 Q_D的设置意在方便地获取私有类指针,文件为qglobal.h.下面的##是宏定义的连字符.假设类名是A,那么A##Private翻译过来就是AP ...
- 《征服 C 指针》摘录6:解读 C 的声明
一.混乱的声明——如何自然地理解 C 的声明? 通常,C 的声明 int hoge; 这样,使用“类型 变量名;”的形式进行书写. 可是,像“指向 int 的指针”类型的变量,却要像下面这样进行声明: ...
随机推荐
- 8.22js前端!
2018-8-22 19:15:19 前端还有一部分就学完了预计这一星期赶一下就可以结束 然后愉快地进行Django框架!!!! 今天中午和呆呆一块吃的大盘鸡,下午和老表我们三个去了日月湖狼了一下午! ...
- 关于webpy模板自动HTML转义的问题
注意: web.py 将会转义任何任何用到的变量,所以当你将 name 的值设为是一段 HTML 时,它会被转义显示成纯文本.如果要关闭该选项,可以写成 $:name 来代替 $name. 如果我们想 ...
- UVM/OVM中的factory【zz】
原文地址:http://bbs.eetop.cn/viewthread.php?tid=452518&extra=&authorid=828160&page=1 在新的项目中再 ...
- jquery给动态添加的dom元素绑定事件
$('input').click(function () { //处理代码 }); 这只能是对已经加载好的元素定义事件,那些后来添加插入的元素则需要另行绑定,对于页面中动态添加的元素,在页面加载完成后 ...
- 删除RAC集群节点
删除GRID集群节点:参考oracle database 11g RAC手册(第二版) 目前GRID集群中节点信息:[grid@node1 ~]$ olsnodesnode1node2node3nod ...
- Buffer和cahce的区别
什么是Cache? 什么是Buffer? 二者的区别是什么? http://wenda.tianya.cn/wenda/thread?tid=595a1d68b3009fed Buffer和Cache ...
- PHP AOP编程思想
AOP思想(面向切面编程) 在应用开发中,我们经常发现需要很多功能,这些功能需要经常被分散在代码中的多个点上,但是这些点事实上跟实际业务没有任何关联.比如,在执行一些特殊任务之前需要确保用户是在登陆状 ...
- JS继承封装
<script> var extend = function (subClass, superClass) { //1.继承类的中间类 var Tmp = function() {}; / ...
- Cable master---poj1064(二分|卡精度)
题目链接:http://poj.org/problem?id=1064 题意:有n条绳子,长度为Li,现在从这n条绳子中切割出K条相等的绳子,问切割出来的这k条绳子的最大长度为多少: 二分判断即可: ...
- ubuntu环境下快速搭建开发环境
接触ubuntu已经半年了,虽然游戏啊qq啊在linux下配置稍微麻烦一些,但是作为开发环境,ubuntu真的是好东西,无论是c啊还是php and etc 看到官网上文档开发环境建议wamp,如果是 ...