https://blog.csdn.net/Moke_8453/article/details/54172587
Qt中有很多如下的片段,d指针,一个Q_D宏声明接d->xxx。这个d指针从哪里来的,类成员变量里面没有,也没有其他很明显的地方。下面我主要来讲一下d指针的含义和好处。
1 private: 2 Q_DECLARE_PRIVATE(QRadioButton) 3 Q_DISABLE_COPY(QRadioButton) 4 friend class QAccessibleButton; 5 6 QRadioButton::QRadioButton(QWidget *parent) 7 : QAbstractButton(*new QRadioButtonPrivate, parent) 8 { 9 Q_D(QRadioButton); 10 d->init(); 11 }
下面这是和所有d指针相关的宏声明(位于global.h文件)
1 template static inline T *qGetPtrHelper(T *ptr) { return ptr; } 2 3 #define Q_DECLARE_PRIVATE(Class) \ 4 inline Class##Private* d_func() { return reinterpret_cast<Class##Private *>(qGetPtrHelper(d_ptr)); } \ 5 inline const Class##Private* d_func() const { return reinterpret_cast<const Class##Private *>(qGetPtrHelper(d_ptr)); } \ 6 friend class Class##Private; 7 8 #define Q_DECLARE_PRIVATE_D(Dptr, Class) \ 9 inline Class##Private* d_func() { return reinterpret_cast<Class##Private *>(Dptr); } \ 10 inline const Class##Private* d_func() const { return reinterpret_cast<const Class##Private *>(Dptr); } \ 11 friend class Class##Private; 12 13 #define Q_DECLARE_PUBLIC(Class) \ 14 inline Class* q_func() { return static_cast >Class *<(q_ptr); } \ 15 inline const Class* q_func() const { return static_cast>const Class *<(q_ptr); } \ 16 friend class Class; 17 18 #define Q_D(Class) Class##Private * const d = d_func() 19 #define Q_Q(Class) Class * const q = q_func()
先来解释一下这个d指针的意义,按照宏声明,他是声明了一个叫做QRadioButtonPrivate *d_func()的函数,然后用reinterpret_cast转换这个指针。至于这里在public和private声明时的reinterpret_cast和static_cast是因为:
reinterpret_cast (expression)
type-id必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,再把该整数转换成原类型的指针,还可以得到原先的指针值)。
static_cast < type-id > (expression)
该运算符把expression转换为type-id类型,但没有运行时类型检查来保证转换的安全性。
①用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。
②用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。
③把空指针转换成目标类型的空指针。
④把任何类型的表达式转换成void类型。
使用d指针的优点
①将具体实现和函数接口分离,解耦合,可以在不改动外部接口的情形下,对内部的实现做改动。
②可以很方便的实现跨平台,和①有关,只需要声明自己的private数据类,根据各个系统下自己去适配系统,然后加入各自的private类头文件即可。接口和实现无关,在各自的私有实现中实现共同的接口即可。
1 #ifdef Q_OS_WIN 2 3 #include <qprocess_win.h> 4 5 #ifdef Q_OS_MAC 6 7 #include <qprocess_mac.h>
③实现层数据封装,有利于二进制兼容性。在版本变动小的情况下,4.8.4的qt库完全可以和4.8.6的dll,互相兼容(小插曲:qt在5.2发版的时候打破了二进制兼容,所以5.2的dll和5.1互相是兼容不了的,至于各个版本之间的具体兼容性,这个楼主没全部测试过,不过小版本的情况下,的确是可以互换的,比如4.8.5到4.8.6)。