Vancamel

千山鸟飞绝,万径人踪灭。 孤舟蓑笠翁,独钓寒江雪。

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

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)。

 

posted on 2019-08-13 15:42  我醉欲眠  阅读(504)  评论(0编辑  收藏  举报