百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

Qt中的Q_D宏和d指针

bigegpt 2024-09-24 07:40 5 浏览

 _ZTS7QObject

一、Q_D的在文件中的提法

  Q_D的设置意在方便地获取私有类指针,文件为qglobal.h。下面的##是宏定义的连字符。假设类名是A,那么A##Private翻译过来就是APrivate。

 #define Q_D(Class) Class##Private * const d = d_func()

  d_func()函数如下实现:

 #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;

  这里的d_func()虽然在宏里面,但是如果代入具体的类型,这里面就变成了以Class##Private的私有类指针为返回值,以func为函数名的函数。这里的qGetPtrHelper是

 template <typename T> static inline T *qGetPtrHelper(T *ptr) { return ptr; }

  这个模板函数里面里的T要套入某个具体的类。上面的那个Q_DECLARE_PRIVATE里面的就成了这个模板类的一个调用。这个模板类就是把这个类指针转换成了静态的。有了上面的这三段代码,如果想在某个类A里面声明一个私有类,直接来一个Q_D(A),再Q_DECLARE_PRIVATE(A)就可以了。

二、宏和模板的展开

  展开前一个宏和后一个宏的一部分,成了

 #define Q_D(A) APrivate *const d= d_func()
 inline APrivate* d_func() { return reinterpret_cast<APrivate *>(qGetPtrHelper((d_ptr));}

  上面这个函数qGetPtrHelper调用的输入值是QObject类里面的一个成员变量,d_ptr指针,定义如下:

     QScopedPointer<QObjectData> d_ptr;

  根据模板函数调用返回的仍然是一个QScopedPointer<QObjectData>类型的变量,也就是一个指向QObjectData类型的智能限域指针。最后调用reinterpret_cast重新解释前面得到的指针,把它变成指向APrivate类型的。

  这里的QObjectData的定义也在QObject里面

  class Q_CORE_EXPORT QObjectData {
  public:
      virtual ~QObjectData() = 0;
      QObject *q_ptr;
      QObject *parent;
      QObjectList children;
  
      uint isWidget : 1;
      uint blockSig : 1;
     uint wasDeleted : 1;
     uint isDeletingChildren : 1;
     uint sendChildEvents : 1;
     uint receiveChildEvents : 1;
     uint isWindow : 1; //for QWindow
     uint unused : 25;
     int postedEvents;
     QDynamicMetaObjectData *metaObject;
     QMetaObject *dynamicMetaObject() const;
 };

  至于QScopedPointer,有点复杂,核心思想是一个不需要自己销毁的指针。

三、继承和调用

  自己写一个类MyQFileSystemModel继承QFileSystemModel,在MyQFileSystemModel中使用Q_D宏,会出现错误:

  C:\Qt\Qt5.9.2\5.9.2\mingw53_32\include\QtWidgets/qfilesystemmodel.h: In constructor 'MyQFileSystemModel::MyQFileSystemModel()':
  C:\Qt\Qt5.9.2\5.9.2\mingw53_32\include/QtCore/qglobal.h:1002:28: error: 'QFileSystemModelPrivate* QFileSystemModel::d_func()' is private
       inline Class##Private* d_func() { return reinterpret_cast<Class##Private *>(qGetPtrHelper(d_ptr)); } \
                              ^
  C:\Qt\Qt5.9.2\5.9.2\mingw53_32\include\QtWidgets/qfilesystemmodel.h:152:5: note: in expansion of macro 'Q_DECLARE_PRIVATE'
       Q_DECLARE_PRIVATE(QFileSystemModel)
       ^
  C:\Qt\Qt5.9.2\5.9.2\mingw53_32\include/QtCore/qglobal.h:1016:54: error: within this context
   #define Q_D(Class) Class##Private * const d = d_func()
                                                       ^
 ..\student\myqfilesystemmodel.cpp:5:5: note: in expansion of macro 'Q_D'
      Q_D(const QFileSystemModel);
      ^
 C:\Qt\Qt5.9.2\5.9.2\mingw53_32\include/QtCore/qglobal.h:1016:43: warning: unused variable 'd' [-Wunused-variable]
  #define Q_D(Class) Class##Private * const d = d_func()
                                            ^
 ..\student\myqfilesystemmodel.cpp:5:5: note: in expansion of macro 'Q_D'

  意思是,d_func()是QFileSystemModel这个类里面的私有函数,对于c++的私有函数,子类是不能够继承的。

四、q指针

  写一个MyQFileSystemModel的私有类MyQFileSystemModelPrivate,就可以使用Q_Q宏,从私有类引用对应的公有类了。

  #ifndef MYQFILESYSTEMMODEL_P_H
  #define MYQFILESYSTEMMODEL_P_H
  #include <myqfilesystemmodel.h>
  class MyQFileSystemModelPrivate;
  class MyQFileSystemModel;
  QT_BEGIN_NAMESPACE
  class MyQFileSystemModelPrivate: public QFileSystemModelPrivate
  {
  public:
     //MyQFileSystemModelPrivate(MyQFileSystemModel * parent):q_ptr(parent){}
 public:
     Q_DECLARE_PUBLIC(MyQFileSystemModel)
     MyQFileSystemModel *q_ptr;
 };
 QT_END_NAMESPACE
 #endif // MYQFILESYSTEMMODEL_P_H

  这里面需要尤其注意的是,MyQFileSystemModel *q_ptr;这一行是不能少的。c++的static_cast是对被转换的类型有限制的。如果B类继承了A类,那么从B类转换成A类是完全没有问题的。但是,如果想把A类转换成B类,就要求B类里面,问题就出现了,A类可能没有B类那么丰满,转换出来的类可能是残废的,所以一般情况下,这种转换是不能成功的。除非:B类里面包含了一个指向A类的指针。如果把q_ptr指针声明去掉了,会报这个错误:

 C:\Qt\Qt5.9.2\5.9.2\mingw53_32\include\QtCore\qglobal.h:1012: error: invalid static_cast from type 'QObject*' to type 'MyQFileSystemModel*'
      inline Class* q_func() { return static_cast<Class *>(q_ptr); } \
                                                                ^

五、私有类函数调用

  Qt中的公有类和私有类关系密切,私有类的函数是不能够直接使用的。要是想用,一定要通过其他类调用。在Qt编译的时候,QFileSystemModel.h是一堆声明,会导出很多函数到QtWidget.dll里面去。值得注意的是,这里导出的只是这个文件里所声明的类、函数和变量,而不会导出只在私有类头文件QFileSystemModel_p.h里面声明过的函数和变量。

  当然,编译的时候,也会引用QFileSystemModelPrivate.h和QFileSystemModel.cpp里的声明以及定义。一般情况下,我们只是Qt的使用者,在windows系统下,只要下载安装就好,不需要自己再编译了。但是当我们想使用私有类做一些更深入的定制的时候,希望能够调直接调用私有类的成员。这时候,如果只是include了.h文件,就会报undefined reference错误。也就是说,编译能过,链接过不了,找不到私有类成员。

  解决的方法就是将对应的cpp文件也包含进工程目录里面,但这时候会有新的问题出现。有些类的实现已经编译到库函数里面了,这时候又在cpp文件重新实现,会报警告:redeclared without dllimport attribute。只需要把cpp文件中的实现函数删除掉就可以了。

  虽然通过上面的方法,可以实现私有类的使用,但是值得注意的是,已经编译好的二进制文件dll里面的同名私有函数还在起着作用。还是用QFileSystemModel为例,它已经被Qt编译好放到了QWidget.dll里面了。在此dll文件里也会有QFileSystemModelPrivate的函数(只是不会有直接指向外部的声明,外部不能直接链接引用而已),否则私有类就完全没用了。当新的工程要使用到QFileSystemModel,而QFileSystemModelPrivate被间接地引用,使用的版本就是之前编译好的成品。当新的工程要直接调用私有类函数的时候,才是用的新的版本。

  用Dependency打开Qt5Widgets.dll看到私有类的函数名形式如下:

 _ZN16QFileSystemModelC1ER23QFileSystemModelPrivateP7QObject

  这可能只是一个构造函数,在Qt5Widgets.dll里只有两个上面这种QFileSystemModelPrivate的函数,可见大多数私有类的函数没有导出。而直接用本节方法编译出来的QFileSystemModelPrivate.dll里面的私有成员函数形式如下:  

 _ZNK23QFileSystemModelPrivate4nodeERK11QModelIndex

  代表形参是QModelIndex的私有类函数node,像这样的函数还有很多,它们与私有类的.h文件能够对应起来。


Qt学习路线:Qt开发技术栈

Qt资料领取:「链接」

相关推荐

5分钟调色大片的方法(5分钟调色大片的方法有哪些)

哈喽大家好。在大家印象中一定觉得ps非常难学非常难。大家不要着急,小编的教学都是针对ps零基础的同学的,而且非常实用哦。只要大家跟着图文练习一两遍,保证大家立马学会~!好了,废话少说,下面开始我们今天...

闪白特效原来是这么用的(闪白特效怎么使用)

作者|高艳侠订阅|010-86092062闪白特效是影视作品中应用比较多的效果之一,那么具体该在哪些场景使用闪白特效?具体该如何操作?下面就以AdobePremiere(以下简称PR)为例,...

ppt常用小图标去哪里找?3个矢量素材网站推荐!

ppt是一个注重可视化表达的演示载体,除了高清图片,ppt中另一类常用的素材是各种小图标,也叫矢量图标,巧妙运用小图标能提升整体美观度和表现力,那么ppt常用小图标去哪里找呢?为方便各位快速找到合适的...

有什么好用的截图录屏工具?试试这9款

经常有朋友反馈苦于缺乏截屏和录屏的趁手工具,本期我们分享几个相当好用的截屏和录屏工具,希望能帮到大家。ScreenToGifScreenToGif是一款免费且开源的录屏工具。此款工具最大的特点是可以...

配色苦手福音!专业快速色环配色PS插件

今天橘子老师给的大家介绍的是一款快速配色的插件,非常强大配色苦手福音来啦!(获取方式见文末)【插件介绍】配色在后期设计中占有主导地位,好的配色能让作品更加抢眼Coolorus这款专业的配色插件,能够...

如何用PS抠主体?(ps怎么抠主体)

1.主体法抠图-抠花苞和花梗导入一张荷花苞的照片,点击上图中顶部“选择”菜单栏,下拉单击“主体”。可以看到,只有花苞被选中,但是花梗并没有被选中。接下来单击上图中左侧工具栏的“快速选择工具”,上图中顶...

2799元的4K电视,有保障吗?(买4k电视机哪个品牌好)

在上一期《电脑报》的3·15专题报道中,我们揭露了一款不靠谱的42英寸4K智能电视——TCLD42A561U。这款售价2699元的4K智能电视不仅4K画质方面存在严重问题,而且各种功能和应用体验也不理...

苹果电脑的Touch Bar推出一段时间了 这款工具可以帮你开发适用于它的APP

距离苹果推出带有TouchBar的MacBookPro已经有一段时间了,除了那些像Adobe、Google和Microsoft大公司在开发适用于TouchBar的应用之外,其实还有很多独立的开...

如魔法般吸取颜色的桌灯(如魔法般吸取颜色的桌灯叫什么)

色彩为生活带来的感官刺激,逐渐被视为理所当然。一盏桌灯运用它的神奇力量,将隐藏于物件中的颜色逐一释放,成为装点环境的空间魔法师。ColorUp是一款可以改变颜色的吸色台灯,沿用传统灯泡的造型,融入了拾...

一篇文章带你用jquery mobile设计颜色拾取器

【一、项目背景】现实生活中,我们经常会遇到配色的问题,这个时候去百度一下RGB表。而RGB表只提供相对于的颜色的RGB值而没有可以验证的模块。我们可以通过jquerymobile去设计颜色的拾取器...

ps拾色器快捷键是什么?(ps2019拾色器快捷键)

ps拾色器快捷键是什么?文章末尾有获取方式,按照以下步骤就能自动获得!学会制作PS特效需要一定程度的耐心和毅力。初学者可以从基本的工具和技术开始学习,逐渐提高他们的技能水平。同时,观看更多优秀的特效作...

免费开源的 Windows 截图录屏工具,支持 OCR 识别和滚动截图等

功能很强大、安装很小巧的免费截图、录屏工具,提供很多使用的工具来帮我么能解决问题,推荐给大家。关于ShareXShareX是一款免费的windows工具,起初是一个小巧的截图工具,经过多年的迭...

入门到精通系列PS教程:第13篇 · 拾色器、颜色问题说明及补充

入门到精通系列PS教程:第13篇·拾色器、颜色问题说明及补充作者|侯潇问题说明我的第12篇教程里,有个小问题没有说清楚。要说是错误,又不算是错误,只是没有说准确。写完那篇教程后,因为已经到了深...

PS冷知识:用吸管工具吸取屏幕上的任意颜色

今天,我们给大家介绍PS中的一个冷知识:用吸管工具可以吸取屏幕上的任意颜色。其实,操作起来是非常简单的。大多数情况下,我们认为,PS的吸管工具只能吸取PS软件作图区域范围内的颜色,最多加上画布四周的...

Windows 11 将提供内置颜色选择器工具

Windows11内置了颜色选择器,可以扫描并识别屏幕上的颜色并生成颜色代码。此外,微软还利用人工智能技术,让屏幕上的文本扫描和选择变得更加便捷。这两项功能均已在SnippingToolv1...