`
美丽的小岛
  • 浏览: 310693 次
  • 性别: 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

    6. 链表操作:`t=t-&gt;___1___ ;` 可能是在进行链表节点的链接操作,如`t-&gt;next`。 7. 内存释放:`free(___1___) ;` 释放动态分配的内存。 8. 循环条件:`while(p!=___1___)` 循环条件检查,直到p不等于某个值为止。...

    C语言习题集合(指针).pdf

    其次,指针的解引用操作是通过对指针变量加星号操作符(*)来完成的,如`*p=*q;`。这表示将q所指向地址中的值赋给p指向的地址。同样,`a=*q;`则是将q所指向地址的值赋给a。 接着,涉及到指针和数组之间的关系。例如...

    数据结构考研真题(09-12)

    #include &lt;stdlib.h&gt; // 定义链表结点 typedef struct Node { int data; struct Node *next; } Node; // 查找倒数第k个结点 int findKthFromEnd(Node *head, int k) { Node *p1 = head-&gt;next; Node *p2 = head...

    2021-2022计算机二级等级考试试题及答案No.11822.docx

    - **选项D**:`p = q-&gt;next;` 这条语句仅将指针p指向了q的下一个结点,并未实现q结点的删除操作。正确的删除操作应该是更新p结点的`next`指针使其指向q结点的下一个结点,然后释放q结点的内存空间。因此,选项D不能...

    递归建立链表

    #include&lt;iostream&gt; #include&lt;stdio.h&gt; #include&lt;malloc.h&gt; using namespace std; struct NODE // 定义节点结构体 { int info; // 存储数据 struct NODE *next; // 指向下一个节点的指针 }; typedef struct NODE ...

    可变长二维数组,行数与每行列数由用户输入

    - `q` 和 `p`: 临时指针变量,分别用于指向当前行和每行元素的数量。 - `i`, `j`: 循环变量。 ##### 4. 获取用户输入的行数 ```c printf("请输入行数:\n"); scanf("%d", &rows); ``` 提示用户输入行数,并读取整数...

    专升本数据结构期末试卷

    6. 删除单链表中结点 A 需要修改指针的操作序列为:q=p-&gt;next;p-&gt;next=q-&gt;next;free(q);知识点:链表的操作。 7. 快速排序的结果是 10,15,14,18,20,36,40,21。知识点:快速排序算法。 8. 二叉排序树的...

    C语言题库(含答案)程序设计语言.pdf

    下面将对题库中的内容进行详细解读。 1. 变量定义和运算符 - int i=10, j=10, k=3; k*=i+j; 这部分代码定义了三个整型变量,并使用复合赋值运算符进行赋值运算。 - k?48324,648k=60; 这是条件运算符的错误书写,...

    看起来混乱无比的代码,却打印出英文歌曲the twelve days of christmas的歌词

    #include&lt;stdio.h&gt; main(t,_,a)char*a;{...} ``` 这里定义了一个`main`函数,它接受三个参数:`t`、`_` 和 `a`,其中 `a` 是一个字符指针。值得注意的是,在 C 语言中,函数名称默认是返回 `int` 类型的值,因此...

    全国计算机二级c上机题库.pdf

    不过,我将尽力从中提炼出可能与计算机编程相关的知识点,并以专业的IT知识进行解读。 1. C语言基础语法知识: 从提供的内容中可以识别出一些C语言的代码片段,比如for循环、if条件判断、while循环等,这些都是...

    关于冒泡排序的完整代码

    printf("%d-", p-&gt;data); p = p-&gt;next; } return h; } ``` 用于打印出链表的所有元素。 4. **链表排序**: ```cpp LinkNode*SortLinkList(LinkNode* h) { // ... (省略具体排序逻辑) } ``` 这是冒泡...

    最新各大公司企业真实面试题-慧通面试题.txt

    scanf("%d", &n); a = (int*)malloc((n + 1) * sizeof(int)); //... for (i = 1; i &lt;= n; i++) { swap(a[i], a[rand() % n + 1]); } ``` - **解读**:这段代码首先通过`malloc`函数动态分配内存,然后通过...

    新视野教育 计算机二级考试试题答案

    4201p-&gt;next02q03p-&gt;next ``` #### 解析: 这部分代码展示了链表的基本操作。`p-&gt;next` 表示链表节点 p 的下一个节点。 ### 题目四十三:链表操作 #### 原始代码: ``` 4301h-&gt;next02p==003r ``` #### 解析: 这...

    基于链表的学生成绩管理系统

    scanf("%d", &p-&gt;number); printf("输入插入的姓名:"); scanf("%s", p-&gt;name); printf("输入插入的成绩:"); scanf("%f", &score); p-&gt;score = score; p-&gt;next = temp-&gt;next; temp-&gt;next = p; return; } ...

    全国2011年10月高等教育自学考试数据结构.pdf

    8. 位运算:文档中出现了位运算符,如 `100010B.D.B.D.B.D.B.D.2A.C.A.C.`,位运算是数据结构中用于执行二进制运算和优化算法性能的重要技术。 由于文档内容不完整并且存在一些识别错误,以上知识点的提炼可能并不...

    内蒙古太仆寺旗宝昌一中2018_2019学年高二物理上学期期中试题

    1. 手机电池符号解读:手机电池上的符号表示了电池的容量和电动势。500 mA·h表示电池的容量,即电池可以以500毫安的电流持续放电1小时;3.6 V是电池的电动势,表示电池能够提供的电压。 2. 电源与电动势:电动势是...

    TPS 丰田式管理读后感

    作者认为,管理者需要掌握有关Q、C、D相关的信息,需善用信息系统与QA支持体制的支持,才能在经营运作的组织制度所付予的权责得以尽情的发挥,使投入资源的极小化达成产品品质极大化的效果。 四、事前管理的经营...

Global site tag (gtag.js) - Google Analytics