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