QT <源码笔记> Q_D Q_Q

QT <源码笔记> Q_D Q_Q

前言

Q_D,Q_Q 指的是QT中的 d_ptr ,q_ptr,
d_ptr:主类中访问私有子类成员指针
q_ptr:私有数据类中访问主类指针

d_ptr ,q_ptr的出现主要是解决QT 程序的二进制兼容性问题
二进制兼容:App.exeV1.0 链接动态库libV1.0, 动态库libV1.0更新到libV1.1 ,App.exeV1.0链接libV1.1且不需要重新编译仍能运行

二进制兼容,在KDE WiKi上面这样描述:

A library is binary compatible, if a program linked dynamically to a former version of the library continues running with newer versions of the library without the need to recompile.
一个动态链接到较早版本的库的程序,在不经过重新编译情况下能够继续运行新版本的库,这样的库即“二进制兼容”。

一、声明

qglobal.h 中定义如下:

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

qglobal.h 中相关其他函数 定义如下:

template <typename T> inline T *qGetPtrHelper(T *ptr) { return ptr; }
template <typename Ptr> inline auto qGetPtrHelper(const Ptr &ptr) -> decltype(ptr.operator->()) { return ptr.operator->(); }

// The body must be a statement:
#define Q_CAST_IGNORE_ALIGN(body) QT_WARNING_PUSH QT_WARNING_DISABLE_GCC("-Wcast-align") body QT_WARNING_POP
#define Q_DECLARE_PRIVATE(Class) \
    inline Class##Private* d_func() \
    { Q_CAST_IGNORE_ALIGN(return reinterpret_cast<Class##Private *>(qGetPtrHelper(d_ptr));) } \
    inline const Class##Private* d_func() const \
    { Q_CAST_IGNORE_ALIGN(return reinterpret_cast<const Class##Private *>(qGetPtrHelper(d_ptr));) } \
    friend class Class##Private;

#define Q_DECLARE_PRIVATE_D(Dptr, Class) \
    inline Class##Private* d_func() \
    { Q_CAST_IGNORE_ALIGN(return reinterpret_cast<Class##Private *>(qGetPtrHelper(Dptr));) } \
    inline const Class##Private* d_func() const \
    { Q_CAST_IGNORE_ALIGN(return reinterpret_cast<const Class##Private *>(qGetPtrHelper(Dptr));) } \
    friend class Class##Private;

#define Q_DECLARE_PUBLIC(Class)                                    \
    inline Class* q_func() { return static_cast<Class *>(q_ptr); } \
    inline const Class* q_func() const { return static_cast<const Class *>(q_ptr); } \
    friend class Class;

二、源码笔记

#define 声明单行宏函数和多行宏函数 本质相同,在涉及多行时回车换行前要加上字符‘\’,即“\回车”,‘\’后紧跟回车键,中间不能有空格或其他字符

1.Class##Private

宏定义中##:以把位于它两边的符号合 成一个符号
如 Class##Private 中Class 为QObject 那么 Class##Private即为 QObjectPrivate。
在QObject 中存在QObjectPrivate类,部分源码如下:

class Q_CORE_EXPORT QObjectPrivate : public QObjectData
{
   Q_DECLARE_PUBLIC(QObject)

public:
   struct ExtraData
   {
       ExtraData() {}
       QList<QByteArray> propertyNames;
       QList<QVariant> propertyValues;
       QList<int> runningTimers;
       QList<QPointer<QObject>> eventFilters;
       QString objectName;
   };

2.template inline T *qGetPtrHelper(T *ptr) { return ptr; }

<1> d_ptr可以是智能指针(例如QScopedPointer),在这种情况下它不能只传递给reinterpret_cast:d_func()必须使用成员函数访问内部指针,因此需要两个版本的宏(在事实上,在qGetPtrHelper存在之前曾经存在过两次). qGetPtrHelper所做的是触发智能指针的隐式转换,当作为参数传递给原始指针时,从而消除了对特殊处理的需要
以Qobject为例 d_ptr 声明如下:
在这里插入图片描述

3、Q_DECLARE_PRIVATE(QObject)

定义当前类的d_func,访问权限为private,将Class##Private(这里是QObjectPrivate)声明为友元类
在这里插入图片描述

4、Q_D(QObject)

#define Q_D(Class) Class##Private * const d = d_func()
将d_ptr 转成Class##Private* const 类型指针,并用于初始化 d ,920行用到d访问threadData,
若存在继承关系则将基类Base##Private * 转换成当前Class##Private *
在这里插入图片描述

5、protected: QObject(QObjectPrivate &dd, QObject *parent = nullptr);

定义protected 的构造函数,实现父类d_ptr的转换,指向将当前类Class##Private*
在这里插入图片描述
在这里插入图片描述

6、Q_Q q_ptr

Q_DECLARE_PUBLIC(Class) 声明q_func 函数,并将Class 声明为友元,Class* q_ptr 定义在Class##Private 中,q_ptr在protected 的构造函数中 赋值为this,
在这里插入图片描述
在这里插入图片描述

总结

在class中 Q_DECLARE_PRIVATE 和 Q_D 配合使用,方便获取d指针,d指针指向Class##Private;
在Class##Private中Q_DECLARE_PUBLIC 和 Q_Q配合使用 ,方便获取q指针,q指针指向原class本身;

参考:

https://blog.csdn.net/tangya3158613488/article/details/87072992
http://www.voidcn.com/article/p-umsfhnvy-bus.html
https://www.cnblogs.com/kuikuitage/p/12825032.html
https://www.cnblogs.com/senior-engineer/p/8065370.html
https://wiki.qt.io/D-Pointer/zh

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值