范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

QtD指针和Q指针及使用

  阅读Qt的源代码的时候,我们经常看Q_D、Q_Q、Q_DECLARE_PRIVATE、Q_DECLARE_PUBLIC这几个宏,这几个宏是干什么用的呢?其实这几个宏就是实现D指针和Q指针的宏,D指针在Qt的源码中大量使用,根本目的在于解决二进制兼容问题。至于什么二进制兼容,可以查阅其他资料,这里只讲Qt中是怎么实现的。1.D指针及Q_指针
  我们先建一个Test类和私有类TestPrivate类,在Test类中添加d_ptr成员,在TestPrivate中添加q_ptr成员。头文件如代码1所示:#ifndef TEST_H #define TEST_H  #include   class TestPrivate;  class Test {     Q_DECLARE_PRIVATE(Test) public:     Test();     virtual ~Test();      void setValue(int v);     int value() const;  protected:     QScopedPointer d_ptr; };  #endif // TEST_H
  代码1
  源文件如代码2所示:#include "test.h"  class TestPrivate {     Q_DECLARE_PUBLIC(Test) public:     Test *q_ptr;     int m_value; };  Test::Test() 	: d_ptr(new TestPrivate) {     d_ptr->q_ptr = this;     d_ptr->m_value = 10; }  Test::~Test() {  }  void Test::setValue(int v) {     Q_D(Test);     if (d->m_value == v)     {         return;     }     d->m_value = v; }  int Test::value() const {     Q_D(const Test);     return d->m_value; }
  代码2
  在上面代码中我们使用了Q_D、Q_DECLARE_PRIVATE、Q_DECLARE_PUBLIC宏,这个几个宏如代码3所示(参看qglobal.h)template  static inline T *qGetPtrHelper(T *ptr) { return ptr; } template  static inline typename Wrapper::pointer qGetPtrHelper(const Wrapper &p) { return p.data(); }  #define Q_DECLARE_PRIVATE(Class)      inline Class##Private* d_func() { return reinterpret_cast(qGetPtrHelper(d_ptr)); }      inline const Class##Private* d_func() const { return reinterpret_cast(qGetPtrHelper(d_ptr)); }      friend class Class##Private;  #define Q_DECLARE_PUBLIC(Class)                                         inline Class* q_func() { return static_cast(q_ptr); }      inline const Class* q_func() const { return static_cast(q_ptr); }      friend class Class;  #define Q_D(Class) Class##Private * const d = d_func() #define Q_Q(Class) Class * const q = q_func()
  代码3
  然后我们可以看到展开之后的头文件如代码4所示:#ifndef TEST_H #define TEST_H  #include   class TestPrivate;  class Test {     inline TestPrivate* d_func() { return reinterpret_cast(d_ptr.data()); }     inline const TestPrivate* d_func() const { return reinterpret_cast(d_ptr.data()); }     friend class TestPrivate; public:     Test();     virtual ~Test();      void setValue(int v);     int value() const;  protected:     QScopedPointer d_ptr; };  #endif // TEST_H
  代码4
  展开之后的源文件如代码5所示:#include "test.h"  class TestPrivate {     inline Test* q_func() { return static_cast(q_ptr); }      inline const Test* q_func() const { return static_cast(q_ptr); }      friend class Test; public:     Test *q_ptr;     int m_value; };  Test::Test() {     d_ptr.reset(new TestPrivate);     d_ptr->q_ptr = this;     d_ptr->m_value = 10; }  Test::~Test() {  }  void Test::setValue(int v) {     TestPrivate * const d = d_func();     if (d->m_value == v)     {         return;     }     d->m_value = v; }  int Test::value() const {     const TestPrivate * const d = d_func();     return d->m_value; }
  代码5
  展开之后我们就可以清晰地看到这几个宏做了什么。以QObject为例,在QObject的源代码中有如代码6所示,在构造函数中实现的d_ptr和q_ptr的初始化,跟上面的Test类似:// 头文件中(qobject.h) class Q_CORE_EXPORT QObject {   	…… protected:     QObject(QObjectPrivate &dd, QObject *parent = Q_NULLPTR);  protected:     QScopedPointer d_ptr;   …… }  // 源文件中(qobject.cpp) QObject::QObject(QObject *parent)     : d_ptr(new QObjectPrivate) {     Q_D(QObject);     d_ptr->q_ptr = this;     …… }
  代码6D指针和Q指针使用
  假如我们的类是从Qt的类继承下来的,以QObject和上面的Test类为例,由于QObject中已经有了d_ptr成员了,而且Qt的类都会有一个类似QObject(QObjectPrivate &dd, QObject *parent = Q_NULLPTR) 这样的受保护的构造函数,现在需要做的就是Test继承QObject、TestPrivate继承QObjectPrivate、在Test的构造函数中调用QObject(QObjectPrivate &dd, QObject *parent = Q_NULLPTR) 这种构造函数。需要注意的是QObjectPrivate是在qobject_p.h头文件中,如果要包含这个头文件,我们需要在pro中添加QT += core-private,然后在代码中添加#include。
  修改之后的头文件如代码7所示:#ifndef TEST_H #define TEST_H  #include   class TestPrivate;  class Test : public QObject {     Q_OBJECT     Q_DECLARE_PRIVATE(Test) public:     Test(QObject *parent = nullptr);     virtual ~Test();      void setValue(int v);     int value() const; };  #endif // TEST_H
  代码7
  修改之后的源文件如代码8所示,注意构造函数的变化和TestPrivate继承QObjectPrivate:#include "test.h" #include   class TestPrivate : public QObjectPrivate {     Q_DECLARE_PUBLIC(Test) public:     int m_value; };  Test::Test(QObject *parent)     : QObject (*(new TestPrivate), parent) {      Q_D(Test);     d->m_value = 10; }  Test::~Test() {  }  void Test::setValue(int v) {     Q_D(Test);     if (d->m_value == v)     {         return;     }     d->m_value = v; }  int Test::value() const {     Q_D(const Test);     return d->m_value; }
  代码8
  假如我们的类是类似最开始Test的那种,就像代码1和代码2那样实现即可,另外如果我们的d指针不是d_ptr而是像m_ptr这样该怎么办?其实Qt还有另外一个宏Q_DECLARE_PRIVATE_D, 只需要把Q_DECLARE_PRIVATE(Test)替换成Q_DECLARE_PRIVATE_D(m_ptr, Test)。
  顺便讲一下Q_PRIVATE_SLOT这个宏,这个宏可以把私有类的成员函数注册共有类的槽函数。还是以Test为例,在头文件中添加代码9:private:     Q_PRIVATE_SLOT(d_func(), void _q_timeout())
  代码9
  在源文件中TestPrivate中添加了一个m_timer和函数_q_timeout ,连接timer的timeout信号,修改之后代码如代码10所示,注意添加最后一行的#include"moc_test.cpp" ,如果不添加的话会导致链接错误:无法解析的外部符号。class TestPrivate : public QObjectPrivate {     Q_DECLARE_PUBLIC(Test) public:     int m_value;     QTimer *m_timer;     void _q_timeout(); };  Test::Test(QObject *parent)     : QObject (*(new TestPrivate), parent) {      Q_D(Test);     d->m_value = 10;     d->m_timer = new QTimer(this);     connect(d->m_timer, SIGNAL(timeout()), this, SLOT(_q_timeout()));     d->m_timer->start(1000); }  ……  void TestPrivate::_q_timeout() {     qDebug() << "time out"; }  #include "moc_test.cpp"
  代码10
  如果Test类可以让其他类继承,使用D指针的话,需要把TestPrivate的声明放到test_p.h中去,就像qobject_p.h那样,继承类就可以使用#include"test_p.h"包含TestPrivate类了。当然还需要为Test添加一个受保护的构造函数Test(TestPrivate &dd, QObject *parent = Q_NULLPTR)。 感兴趣的小伙伴可以自己实现一下。看看有没有什么问题。
  好了,关于D指针和Q指针就讲到这里了,大家有什么想知道了,可以在评论区告诉我,有空的时候帮大家整理出来。

假如中国移动推出4G无限流量,WiFi还有存在的必要吗?以中国移动的尿性,要么是内部人员,要么得花高价,才能获得无限流量。相对WIFI来说,门槛低,一人花钱大家收益,所以存在很有必要。另外无限流量不等于随时随地都可以高速上网啊,比如说人通联支付帕克云有哪些功能?就是停车智能了,那些功能也都会围绕智能展开的,带来的就是方便,无论对管理方还是车主来说都是好事,比如不需要人值守,对管理方来说省去了人工成本,对车主来说省去了等待的时间,停车效率提中国银联手机闪付功能上新支持一键绑卡免输卡号今日,针对此前在ApplePay绑银行卡要随身带银行卡,扫描卡片或手动输入银行卡号的问题,中国银联官方表示,银联手机闪付ApplePay一键绑卡功能上线。中国银联官方公布的具体步骤性价比和安全之选,西数Mypassport随行版移动硬盘树立国潮新形象身为数码爱好者,当然任何关于数码产品的最新动态都不能错过。这不最近在网上看到西Mypassport移动硬盘发布了一套国潮系列海报,在整个国潮海报的视觉不难看出,整个画风都是根据产品联想ZUI13forPad系统曝光超级互联隐私神盾等功能今日联想小新发布视频,详细展现了即将推出的ZUI13forPad系统核心功能。该系统在UI功能等方面进行了全新升级,预计将随小新PadPro12。6平板电脑推出。联想ZUI13系统有人说看今日头条耗电快,这是为什么?对于今日头条的耗电我颇有体会先给大家看一项数据看到没有,今日头条可一直在后台待着安卓用户应该深有体会,不论怎么关闭今日头条后台的进程,它都会在几分钟后复活。。当你在今日头条中不断的两家人拉一根电信宽带线入户供日常使用,有问题吗?根据我所知道回答一下这个问题。现在运营商提供的家庭入户接入带宽每年都在提速,100M的接入带宽已经很平常,大部分升级到了200M300M,有些地区升级到500M。两家人共享一个电线苹果和华为拒绝,高通还能拯救自己吗?感谢您的阅读!高通的主营业务主要是QCTQTL和QSI三大部分。而QCT主要是指骁龙处理器,在20122017年,高通骁龙处理器的收入始终排名高通总收入的第一位,在2017年更是收2021年随身WiFi的天花板?Linksys5G随身WiFi6路由器深度评测Hello,大家好!我是沈少!在2021年WiFi6技术已经逐渐成为主流的大背景下,我们突然发现手机电脑传统路由器产品中支持WiFi6技术的已经越来越多,但随身路由确大多还是用上一华为低价5G手机有货了!128GB鸿蒙系统,还带有充电器手机市场国内的手机市场现如今的厂商在发布手机产品的时候啊,很多都开始不带充电器了,不过其背后的更本原因就在于现如今的处理器市场。在华为陷入危机之后啊,在手机市场上消费者们都开始关注下一部手机你会换苹果还是华为?我用三部手机已经前后要5年多了都是华为的。我喜爱华为,功能强大,灵敏度速度都很好,而且是国货,我更要用华为。诺基亚,我再给你一次机会灵光一闪灵光一闪灵光一闪已習慣使用蘋果手機,沒有
从小众走向盈利?科技企业寻找元宇宙赚钱模式西班牙人报网站近日报道称,元宇宙这个词最早出现在美国人尼尔斯蒂芬森的科幻小说雪崩中。从那时起,这个词就被用来描述物理和虚拟空间之间的融合,但直到去年它才成为一个非常流行的表达方式。2022这4款手机拍照最好,堪比小单反,经常拍照的朋友可以考虑喜欢去各地拍照旅游的朋友,可能随身携带相机不方便,但是大部分手机的拍照效果并不如相机,小编给大家盘点了以下几款堪比小单反的手机,经常拍照的朋友可以考虑。第一款VIVOX70Pro上配置豪华,颜值升级京东云无线宝AX6600雅典娜评测随着5G的普及,流量时代即将到来,然而就现在来说,传统的路由器在家里还是无法被完全替代。两年前,我为了wifi6,将家里的路由器换成了京东云无线宝,本意只是为了更快地上网,它却给我印度华星5月产能将达到200万已通过三家世界TOP级客户的审厂认证印度华星5月产能将达到200万已通过三家世界TOP级客户的审厂认证财联社4月1日电,TCL华星COO赵军称印度华星目前正在进行产能的爬坡,3月产能已经达到了约120万。到5月份会实新一波财富大转移已到来,你准备好了吗?近几天两条消息引起热议一是,互联网大厂纷纷裁员,比例还相当高二是,新能源汽车高薪抢人。某些企业开出了软件高级专家年薪6080万总监级年薪100万以上的薪酬。有点冰火两重天的感觉。2单片机内部基本原理bin文件如何跑起来编译器做了什么?无论是单片机还是cpu内部主要有三种部件ALU控制器寄存器。这个要从编译器开始讲起,编译器会给你编写的软件增加一个头部,无论是MDK还是IAR等等,这个头部是做了什么工作那?头部主CentOS应该使用哪些Linux命令行测试网速带宽?一安装speedtestclispeedtestcli是一个用Python编写的轻量级Linux命令行工具,在Python2。4至3。4版本下均可运行。它基于Speedtest。n宇宙之外是否有更高等级的文明我们人类生活所在的时空或者宇宙是怎么出现的?目前一个广泛接受的理论模型就是我们这个宇宙产生于大约140亿年前的一次大爆炸。该模型主要基于现有的探测结果,即星系正在加速彼此远离,越是专业纯粹影音而生,泰捷电视盒子WE60C2升级版体验电视盒子发展多年,同质化十分严重。虽然如今智能电视深入普及,但面对着有限的机能和开机就弹出的电视广告,留给电视盒子的市场仍然广阔。相较于手机飞快的更新换代速度,电视盒子推陈出新的力阿里P9右军的20年职场独白在职场中,努力是一件重要的事情,但并不是最重要的事情。想要在职场上一路升级打怪,有些东西是你必须要了解的。今天推荐中生代技术(IDfreshmanTechnology)的一篇文章,又是配件猪队友,小米12Pro后盖设计曝光根据gsmarena的消息,一组手机壳渲染图曝光了小米12Pro的背面设计,图片上总共出现了5个摄像头开孔,其中三个为摄像头,一个为LED闪光灯和另外一个则为机身对面的传感器,但目