解读 Q_D, Q_Q 指针<转>

d指针是在主类中使用的,来获取私有子类成员指针

q指针是在私有数据类中使用的,来获取主类对象指针

D-指针
私有成员总是不可见的,Qt中私有成员不仅仅是简单封装一下,将访问权限改为private,它将所有私有数据封装在私有类里(命名就是 classname##private), 这样一来连用户都不知道他到底封装了什么,程序中只有这个私有类成员指针,这个指针就是D-指针。

QObject开始看

[c-sharp]

1.  class QObject

2.  {

3.  Q_DECLARE_PRIVATE(QObject)

4.  public:

5.  Q_INVOKABLE explicit QObject(QObject *parent=0);

6.  protected:

7.  QObject(QObjectPrivate &dd, QObject *parent = 0);

8.  QScopedPointer<QObjectData> d_ptr;

9.  // others

10.}

展开后

[c-sharp]

1.  class QObject

2.  {

3.  inline QObjectPrivate* d_func() { return reinterpret_cast(qGetPtrHelper(d_ptr)); }

4.  inline const QObjectPrivate* d_func() const { return reinterpret_cast(qGetPtrHelper(d_ptr)); }

5.  friend class QObjectPrivate;

6.  public:

7.  Q_INVOKABLE explicit QObject(QObject *parent=0);

8.  protected:

9.  QObject(QObjectPrivate &dd, QObject *parent = 0);

10.QScopedPointer<QObjectData> d_ptr;

11.// others

12.}

QObject的构造函数如下:

[c-sharp]

1.  QObject::QObject(QObject *parent)

2.  : d_ptr(new QObjectPrivate)

3.  {

4.  // others

5.  }

6.  QObject::QObject(QObjectPrivate &dd, QObject *parent)

7.  : d_ptr(&dd)

8.  {

9.  // others

10.}

也就是QObjectData *d_ptr = new QObjectPrivate

显然QObjectPrivate 继承了 QObjectData

如下

[c-sharp]

1.  QObjectData {

2.  public:

3.  virtual ~QObjectData() = 0;

4.  // others

5.  };

[c-sharp]

1.  class Q_CORE_EXPORT QObjectPrivate : public QObjectData

2.  {

3.  Q_DECLARE_PUBLIC(QObject)

4.  public:

5.  QObjectPrivate(int version = QObjectPrivateVersion);

6.  virtual ~QObjectPrivate();

7.  // others

8.  }

看看QObject的一个方法

[c-sh

1.  QString QObject::objectName() const

2.  {

3.  Q_D(const QObject);

4.  return d->objectName;

5.  }

展开后

[c-sharp]

1.  QString QObject::objectName() const

2.  {

3.  QObjectPrivate * const d = d_func()

4.  return d->objectName;

5.  }

所以Qt 为我们把从 d_func() 获取 QObjectPrivate 指针的代码给封装起来了,之后就可以直接使用d->

QObject的第二个构造函数使用传入的 QObjectPrivate 对象,但它是 protected 的,也就是说,你不能在外部类中使用这个构造函数。那么这个构造函数有什么用呢?我们来看一下 QWidget 的代码:

[c-]

1.  class: public QObject, public QPaintDevice

2.  {

3.  Q_OBJECT

4.  Q_DECLARE_PRIVATE(QWidget)

5.  // others

6.  }

QWidget QObject 的子类,然后看它的构造函数:

 

1.  QWidget::QWidget(QWidgetPrivate &dd, QWidget* parent, Qt::WindowFlags f)

2.  : QObject(dd, 0), QPaintDevice()

3.  {

4.  Q_D(QWidget);

5.  QT_TRY {

6.  d->init(parent, f);

7.  } QT_CATCH(...) {

8.  QWidgetExceptionCleaner::cleanup(this, d_func());

9.  QT_RETHROW;

10.}

11.}

显然了QWidgetPrivate 继承了QObjectPrivate

于是我们已经明白,为什么 QWidget 中找不到 d_ptr 了,因为所有的 d_ptr 都已经在父类 QObject 中定义好了!尝试展开一下 Q_DECLARE_PRIVATE 宏,你就能够发现,它实际上把父类的 QObjectPrivate 指针偷偷地转换成了 QWidgetPrivate 的指针。

因此有如下结论:

1、在基类中定义一个protected权限的基类私有类d_ptr指针;

2、在每个派生类中用本类私有类初始化d_ptr(该私有类需要继承基类私有类),并定义d_func(),获取基类d_ptr,这个d_func()是由 Q_DECLARE_PRIVATE展开得来的并将其转换为当前私有类指针;


3、在函数中使用Q_D,这样就可以使用d了;
4、在私有数据继承体系中,不要忘记将析构函数定义为虚函数,基类析构函数中释放d_ptr,以防内存泄露!!!

============================================================

Q-指针
q指针是在私有数据类中使用的,来获取主类指针。

[cpp]  

1.  class Q_CORE_EXPORT QObjectPrivate : public QObjectData

2.  {

3.  Q_DECLARE_PUBLIC(QObject)

4.  public:

5.  //others...

6.  };

展开后:

[cpp] 

1.  class Q_CORE_EXPORT QObjectPrivate : public QObjectData

2.  {

3.  inline QObject* q_func() { returnstatic_cast<QObject *>(q_ptr); } /

4.  inlineconst QObject* q_func() const { returnstatic_cast<const QObject *>(q_ptr); } /

5.  friendclass QObject;

6.  //others

7.  }

QObjectData定义如下:

[cpp] 

1.  QObjectData {

2.  public:

3.  QObject *q_ptr;

4.  //others

5.  }

6.  #define Q_Q(QObject) QObject * const q = q_func()

三、使用的例子:

在使用调色板中

[cpp] 

1.  void QWidget::setPalette(const QPalette &palette)

2.  {

3.  Q_D(QWidget); //得到私有成员 QWidgetPrivate指针 d

4.  setAttribute(Qt::WA_SetPalette, palette.resolve() != 0);

5.  QPalette naturalPalette = d->naturalWidgetPalette(d->inheritedPaletteResolveMask);

6.  QPalette resolvedPalette = palette.resolve(naturalPalette);

7.  d->setPalette_helper(resolvedPalette); //调用QWidgetPrivate::setPalette_helper()

8.  }

9.  void QWidgetPrivate::setPalette_helper(const QPalette &palette)

10.{

11.Q_Q(QWidget);

12.if (data.pal == palette && data.pal.resolve() == palette.resolve())

13.return;

14.data.pal = palette;

15.updateSystemBackground();

16.propagatePaletteChange();

17.updateIsOpaque();

18.q->update(); //调用QWidget::update()

19.updateIsOpaque();

20.}

 

#define Q_DECLARE_PRIVATE(Class) \
inline Class##Private* d_func() { return reinterpret_cast<Class##Private *>(qGetPtrHelper(d_ptr)); } \
inline const Class##Private* d_func() const { 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() { return reinterpret_cast<Class##Private *>(Dptr); } \
inline const Class##Private* d_func() const { return reinterpret_cast<const Class##Private *>(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 Q_D(Class) Class##Private * const d = d_func()
#define Q_Q(Class) Class * const q = q_func()

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值