1. d指针
-
作用
-
隐藏接口具体实现细节
-
提高程序编译速度
-
最大程度实现二进制兼容
-
二进制兼容动态库:动态链接到库的前一个版本的程序继续与库的新版本一起运行而不需要重新编译,则库是二进制兼容的。程序需要重新编译以使用新版本的库运行,但不需要任何进一步的修改,则该库是源代码兼容的。
-
如何使动态库二进制兼容:就要求每一个结构以及每一个对象的数据模型保持不变。所谓“数据模型保持不变”,就是不能在类中增加、删除数据成员
-
方法:1.预先分配若干个保留空间,后续添加数据使用保留空间(使用位域:int n:20)
2.将预分配保留空间类型由常规变量改为对象指针
也就是让所有的共有类都拥有一个指针,这个指针包含所有数据的私有数据结构。且这个私有的数据结构可在任意版本中修改,从而不影响该类的使用,因为这个指针是私有的,外部调用只能看到一个不变化的共有类,该共有类只拥有一个指针,这个指针就是称为d指针的Q_D指针。
-
-
Q_DECLARE_PRIVATE
和Q_D
配合使用是为了获取d指针,d指针指向Class##Private
私有类
-
// 第一种
class Q_CORE_EXPORT QObjectData {
Q_DISABLE_COPY(QObjectData)
public:
QObjectData() = default;
virtual ~QObjectData() = 0;
QObject *q_ptr;
QObject *parent;
QObjectList children;
uint isWidget : 1;
uint blockSig : 1;
uint wasDeleted : 1;
uint isDeletingChildren : 1;
uint sendChildEvents : 1;
uint receiveChildEvents : 1;
uint isWindow : 1; //for QWindow
uint deleteLaterCalled : 1;
uint unused : 24;
int postedEvents;
QDynamicMetaObjectData *metaObject;
QMetaObject *dynamicMetaObject() const;
#ifdef QT_DEBUG
enum { CheckForParentChildLoopsWarnDepth = 4096 };
#endif
};
//第二种
class Q_CORE_EXPORT QObject
{
// Q_DECLARE_PRIVATE作用:定义当前类内联函数d_fun() 并使其指向私有类的实现,同时将私有类声明位-当前类的友元类
Q_DECLARE_PRIVATE(QObject)
protected:
QScopedPointer<QObjectData> d_ptr;
};
QObject::QObject(QObjectPrivate &dd, QObject *parent)
: d_ptr(&dd)
{
Q_ASSERT_X(this != parent, Q_FUNC_INFO, "Cannot parent a QObject to itself");
// Q_D 作用:Q_D只作用于当前函数作用域,在每个函数的第一行使用,定义了一个QObjectPrivate的常量指针 指向d_func() ,因此通过Q_D 可以访问d指针
// d指针需要手动释放,但是QT中使用的是QScopedPointer 无需手动释放
Q_D(QObject);
d_ptr->q_ptr = this;
//...
}
// <------------------ Q_DECLARE_PRIVATE 宏定义解析 ------------------->
#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;
//------------------转换后
inline QObjectPrivate* d_func()
{
return reinterpret_cast<QObjectPrivate *>(qGetPtrHelper(d_ptr));
}
inline const QObjectPrivate* d_func() const
{S
return reinterpret_cast<const QObjectPrivate *>(qGetPtrHelper(d_ptr));
}
friend class QObjectPrivate;
// <------------------ Q_D ------------------ >
#define Q_D(Class) Class##Private * const d = d_func()
//------------------转换后
QObjectPrivate* const d = d_func()
2. q指针
- 作用:配合d指针实现d指针的作用
Q_DECLARE_PUBLIC
和Q_Q
配合:在C lass##Private中方便获取q指针,q指针指向原class本身
class Q_CORE_EXPORT QObjectPrivate : public QObjectData
{
Q_DECLARE_PUBLIC(QObject)
// ...
};
// <------------------ Q_DECLARE_PUBLIC 宏定义解析 ------------------->
#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;
//------------------转换后
// Q_DECLARE_PUBLIC 作用:定义q_fun() 并使其之前关联类,同时将关联类声明位当前类的友元类
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;
// <------------------ Q_Q 宏定义解析 ------------------->
#define Q_Q(Class) Class * const q = q_func()
//------------------转换后
// Q_Q 只作用域当前函数的作用域,在每一个函数中第一行使用
// Q_Q 定义类一个QObjectPrivate常量指针指向q_fun() 因此通过Q_Q可以访问q_指针
QObject * const q = q_func()