`
美丽的小岛
  • 浏览: 296987 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

解读 Q_D, Q_Q 指针<转>

    博客分类:
  • QT
 
阅读更多

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

分享到:
评论

相关推荐

    智能指针类型转换.pdf

    为了⽀持这样的⽤法,shared_ptr提供了类似的转型函数 static_pointer_cast&lt;T&gt;()、const_pointer_cast&lt;T&gt;()、dynamic_pointer_cast&lt;T&gt;(),它们与标准的转型操作符static_cast&lt;T&gt;()、const_cast&lt;T&gt;()和dynamic_cast&lt;T...

    RRGRID

    lParam --值&lt;br&gt;#define GM_SET_ROW_MODIFY WM_GRID_USER_OUTER + 43&lt;br&gt;&lt;br&gt;//得到单元修改标志:wParam -- GridCell_T指针&lt;br&gt;//退出编辑之后该标志是无效的&lt;br&gt;//可以在GN_EXIT_CELL_EDITBOX通知中获得该标志...

    C#编程经验技巧宝典

    58&lt;br&gt;&lt;br&gt;0081 文本中首字母改为大写 59&lt;br&gt;&lt;br&gt;0082 C#随机数的产生 59&lt;br&gt;&lt;br&gt;0083 身份证从15位升至18位算法 60&lt;br&gt;&lt;br&gt;0084 十进制数转二进制数的算法 60&lt;br&gt;&lt;br&gt;0085 十进制数转八进制数的算法 61...

    c语言时间片

    //链接指针&lt;br&gt;int reach_time;//到达时间&lt;br&gt;int left_time;//估计运行时间&lt;br&gt;int run_time;//已运行时间&lt;br&gt;char status;//R就绪 c完成&lt;br&gt;PCB();&lt;br&gt;PCB(char aname,int areach_time,int aleft_time,int arun_...

    07_31_C_01_指针和指针赋值&外挂原理

    07_31_C_01_指针和指针赋值&外挂原理07_31_C_01_指针和指针赋值&外挂原理07_31_C_01_指针和指针赋值&外挂原理07_31_C_01_指针和指针赋值&外挂原理07_31_C_01_指针和指针赋值&外挂原理07_31_C_01_指针和指针赋值&外挂...

    指针经验总结

    PDF格式&lt;br&gt;让你不再害怕指针&lt;br&gt;&lt;br&gt;前言:复杂类型说明&lt;br&gt;1、细说指针&lt;br&gt; 1.指针的类型&lt;br&gt; 2.指针所指向的类型&lt;br&gt; 3.指针的值----或者叫指针所指向的内存区或地址&lt;br&gt; 4指针本身所占据的内存区&lt;br&gt;2、指针的...

    Visual C++ 编程资源大全(控件 其它)

    BOOKMARK.ZIP &lt;br&gt;BOOKMARK控件(20KB)&lt;END&gt;&lt;br&gt;18,AresButtonPro.ZIP &lt;br&gt;任意形状立体动态按钮(306KB)&lt;END&gt;&lt;br&gt;19,SysTray.ZIP &lt;br&gt;托盘控件(9KB)&lt;END&gt; &lt;br&gt;20,Recorder.ZIP &lt;br&gt;录音控件(15KB)&lt;END&gt;&lt;br&gt;21,...

    08_01_C_02_二级指针&函数指针

    08_01_C_02_二级指针&函数指针08_01_C_02_二级指针&函数指针08_01_C_02_二级指针&函数指针08_01_C_02_二级指针&函数指针08_01_C_02_二级指针&函数指针08_01_C_02_二级指针&函数指针08_01_C_02_二级指针&函数指针08_...

    数据结构(C++)有关练习题

    &lt;br&gt;内容及步骤:&lt;br&gt;1、 在前一个实验的基础上,继续增加搜索函数Search(int Info)(如果找到结点,返回指向该结点的指针,如果没有,则返回空指针)和删除函数bool Delete(int Info),如果找到结点,则删除该结点,并...

    myagent22

    &lt;br&gt; }&lt;br&gt; 获取剪贴板信息并且朗读:&lt;br&gt; void ReadClipText()&lt;br&gt; {&lt;br&gt; if( g_bAgentOK)&lt;br&gt; { &lt;br&gt; // 只有文本文件才朗读&lt;br&gt; if( IsClipboardFormatAvailable(CF_TEXT))&lt;br&gt; {&lt;br&gt; if (OpenClipboard(g_...

    C源代码实例集

    &lt;br&gt;第三部分 数值计算与趣味数学篇&lt;br&gt; &lt;br&gt;075 绘制余弦曲线和直线的迭加&lt;br&gt;076 计算高次方数的尾数 &lt;br&gt;077 打鱼还是晒网 &lt;br&gt;078 怎样存钱以获取最大利息 &lt;br&gt;079 阿姆斯特朗数 &lt;br&gt;080 亲密数 &lt;br&gt;081 自守数 ...

    编译原理词法分析器

    【说明】 一下规则为我们学校要求的 各个具体题目不一样 根据需要进行修改&lt;br&gt;&lt;br&gt;...否找到s,返回&lt;br&gt;入口指针&lt;br&gt;int to10(char s[],int n)&lt;br&gt; 输入:数字字符串s,s的进制数n&lt;br&gt; 输出:由s转化成的十进制数&lt;br&gt;

    VC MFC专题讲座 chm

    看好在下:&lt;br&gt;第一章 CGI &lt;br&gt;第二章 ACTIVEX&lt;br&gt;第三章:异常处理&lt;br&gt;第四章 多线程/多进程&lt;br&gt;……&lt;br&gt;……&lt;br&gt;1.1 如何编写CGI程序&lt;br&gt;&lt;br&gt;CGI的工作原理介绍:CGI(Common Gateway Interface)是一个WEB服务器...

    const 指针

    &lt;类型&gt; const * &lt;指针变量&gt; 或 const &lt;类型&gt; * &lt;指针变量&gt; 2、常量指针: &lt;类型&gt; * const &lt;指针变量&gt; 3、指向常量的常量指针: &lt;类型&gt; const * const &lt;指针变量&gt; 或 const &lt;类型&gt; * const &lt;指针变量&gt;

    qsort

    base 待排序的数组,melem 数组的元素个数,width 每个元素的大小,&lt;br&gt; fcmp 用于对数组元素进行比较的函数指针,该函数由自己另外编写,有2个参数.&lt;br&gt;&lt;br&gt;所属文件: &lt;stdlib.h&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;

    ICTC-6

    &lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;(图一)&lt;br&gt;&lt;br&gt;根据上篇文章内容,该图该可以等价于如下的二维表格表示:&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;(图二)&lt;br&gt;&lt;br&gt;而对应于该表格的是一个ColumnFirstDynamicArray,共有10个结点,每个结点的取值如下表...

    ATL实现的CDHtmlDialog模板类

    这个文件提供了若干个类和模板类,开发者只需关注其中两个模板类:CDHtmlDialogImpl&lt;&gt;和CMultiPageDHtmlDialogImpl&lt;&gt;,第一个模板类实现了WEB页面布局的对话框,第二个模板类以第一个类为基础,扩展成了在一个对话框...

    数据结构算法与应用 很详细的,数据结构算法全集 这个是你想找的

    图 365&lt;br&gt;12.1 基本概念 365&lt;br&gt;12.2 应用 366&lt;br&gt;12.3 特性 368&lt;br&gt;12.4 抽象数据类型Graph和Digraph 370&lt;br&gt;12.5 无向图和有向图的描述 371&lt;br&gt;12.5.1 邻接矩阵 371&lt;br&gt;12.5.2 邻接压缩表 373&lt;br&gt;12.5.3 邻接链表...

    08_07_C_04_结构体指针

    08_07_C_04_结构体指针08_07_C_04_结构体指针08_07_C_04_结构体指针08_07_C_04_结构体指针08_07_C_04_结构体指针08_07_C_04_结构体指针08_07_C_04_结构体指针08_07_C_04_结构体指针08_07_C_04_结构体指针08_07_C_04_...

    智能指针shared-ptr的初始化.pdf

    智能指针 智能指针shared_ptr的初始化 的初始化 shared_ptr是智能指针,是模板,头⽂件是memory: shared_ptr&lt;string&gt; p1 最安全的使⽤⽅法是调⽤make_shared标准库函数,此函数在动态内存中分配⼀个对象并初始化它...

Global site tag (gtag.js) - Google Analytics