qt源码阅读准备

news2024/11/27 20:59:08

qt源码阅读准备

阅读qt源码前先了解以下知识,对阅读qt源码有极大的好处。

D-pointer介绍

D-pointer介绍

d-pointer它可以把一个类库的实施细节对使用的用户隐藏, 而且对实施的更改不会打破二进制兼容。其基本贯穿qt所有类。

Qt类的的结构

我们以QObject举例:
QObject对象叫行为类,QObjectPrivate叫数据类。
QT中大多数类的组织结构:
行为类中包含一个私有的指向数据类的指针d_ptr(就是所谓的d-pointer),
数据类中包含一个指向行为类指针q_ptr,
并且数据类对外不可见一般声明在行为类的cpp文件中。
我将QObject结构简化如下:

QObject.h文件:
class QObjectPrivate;//因为数据类对外应该不可见,所以这里仅声明
class QObject
{
    Q_OBJECT
    Q_DECLARE_PRIVATE(QObject)
public:
    QObject(QObject *parent=nullptr);
protected:
    QObject(QObjectPrivate &dd, QObject *parent = nullptr);
protected:
    //QScopedPointer定义智能指针
    QScopedPointer<QObjectData> d_ptr;//这就是传说中的d-pointer,
};

QObject.cpp文件:
//数据类声明在行为类的cpp文件中或单独声明在一个文件中时,仅在行为类的cpp中引用其头文件

class QObjectData {
public:
    QObject *q_ptr;//包含一个行为类成员q_ptr  
};

class QObjectPrivate : public QObjectData
{
    Q_DECLARE_PUBLIC(QObject)
public:
    QObjectPrivate(int version = QObjectPrivateVersion);
} 

行为类和数据类关联实现如下:

//数据对象初始化q_ptr为空
QObjectPrivate::QObjectPrivate(int version)
{
    q_ptr = nullptr;  
}

//public构造函数调用protected构造函数时会new一个数据类对象
QObject::QObject(QObject *parent) : QObject(*new QObjectPrivate, parent)
{
}

//将数据类对象传给d_ptr
QObject::QObject(QObjectPrivate &dd, QObject *parent) : d_ptr(&dd)
{
    Q_D(QObject);
    d_ptr->q_ptr = this;//将数据类的q_ptr指向行为类对象,即自己
}
//构造完成后行为类和数据类都相互保存对方的指针
//后面在行为类函数中就可以通过Q_D获取数据类对象
//在数据类函数中就可以通过Q_Q获取行为类对象

Q_DECLARE_PRIVATE

此宏定义在行为类中,定义了获取数据对象d_ptr的函数d_func
主要是为了后面的宏Q_D使用。
简化其定义如下:

宏定义中的##表示连接字符串
#define Q_DECLARE_PRIVATE(Class) \
    Class##Private* d_func() \
    {
         return d_ptr; \
    } \
     const Class##Private* d_func() const \
    {\ 
        return d_ptr; \
    } \
    friend class Class##Private;

Q_DECLARE_PRIVATE(QObject)转换后如下:
    QObjectPrivate* d_func() 
    {
         return d_ptr; 
    } 
     const QObjectPrivate* d_func() const 
    {
        return d_ptr; 
    }
    friend class QObjectPrivate;

Q_DECLARE_PUBLIC

此宏定义在数据类中,定义了获取行为对象的函数q_func
主要是为了后面的宏Q_Q使用。
简化其定义如下:

#define Q_DECLARE_PUBLIC(Class)  \
    Class* q_func() \
    { \
         return q_ptr; \ 
         } \
    const Class* q_func() const\
    { \
         return q_ptr; \
    } \
    friend class Class;

Q_DECLARE_PUBLIC(QObject)转换后如下:
    QObject* q_func()
    { 
        return q_ptr; 
    } 
    const QObject* q_func() const
    {
        return q_ptr;
    }
    friend class QObject;

Q_D

此宏在行为类函数中使用,用来定义一个指向数据对象d_ptr的指针d,
以供函数后面直接使用d
其定义如下:

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

Q_D(QObject);转换后:QObjectPrivate * const d = d_func();
由Q_DECLARE_PRIVATE(QObject)可知d_func返回的是d_ptr

void QObject::setParent(QObject *parent)
{
    Q_D(QObject);//转换后为QObjectPrivate * const d = d_ptr;
    d->setParent_helper(parent);//可以直接使用d指针操作数据类对象
}

Q_Q

此宏在数据类函数中使用,用来定义一个指向行为类对象q_ptr的指针q,
以供函数后面直接使用q
其定义如下:

#define Q_Q(Class) Class * const q = q_func()

Q_Q(QObject);转换后QObject * const q = q_func();
由Q_DECLARE_PUBLIC(QObject)可知q_func返回的是q_ptr

void QObjectPrivate::moveToThread_helper()
{
    Q_Q(QObject);//QObject * const q = q_ptr;
    QEvent e(QEvent::ThreadChange);
    QCoreApplication::sendEvent(q, &e);
    ...
}

Q_OBJECT

此宏用于定义元对象,需要使用QObject的信号关联必须定义此宏,并且需要在类定义最前面定义此宏

简化定义如下:
#define Q_OBJECT \
public: \
    static const QMetaObject staticMetaObject; \
    virtual const QMetaObject *metaObject() const; \
    virtual void *qt_metacast(const char *); \
    virtual int qt_metacall(QMetaObject::Call, int, void **); \
private: \
    static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); \
    struct QPrivateSignal {}; \

QMetaObject元对象保存了类的基本信息是对类的描述,记录了类名称,槽、信号、函数数量偏移等。QMetaObject对象的初始化是通过qt元对象编译器moc编译后自动生成的。

继承QObject的类结构

继承QObject的类都有自己的特有数据类,其继承了QObject数据对象类。
在构造过程中是将自己的数据对象类,最终传给父亲类QObject的d_ptr,
也保证了每个对象仅有一个数据对象类指针,而不是每层级都有自己的d_ptr
在这里插入图片描述

1、
class QFtpPrivate : public QObjectPrivate
{};
//直接调用QObject的protected构造函数传入QObjectPrivate指针
QFtp::QFtp(QObject *parent) : QObject(*new QFtpPrivate, parent)
{
}

2、
class QActionGroupPrivate : public QObjectPrivate
{};
QActionGroup::QActionGroup(QObject* parent) : QObject(*new QActionGroupPrivate, parent)
{
}

3、
class  QWidgetPrivate : public QObjectPrivate
{};

class  QWidget : public QObject, public QPaintDevice
{
public:
 explicit QWidget(QWidget* parent = nullptr, Qt::WindowFlags);
protected:
    QWidget(QWidgetPrivate &d, QWidget* parent, Qt::WindowFlags f);
};

QWidget::QWidget(QWidget *parent, Qt::WindowFlags f) : QObject(*new QWidgetPrivate, nullptr), QPaintDevice()
{
}

QWidget::QWidget(QWidgetPrivate &dd, QWidget* parent, Qt::WindowFlags f) : QObject(dd, nullptr), QPaintDevice()
{
}

get(QWidget *parent, Qt::WindowFlags f) : QObject(*new QWidgetPrivate, nullptr), QPaintDevice()
{
}

QWidget::QWidget(QWidgetPrivate &dd, QWidget* parent, Qt::WindowFlags f) : QObject(dd, nullptr), QPaintDevice()
{
}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1357065.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【unity】基于Obi的绳/杆蓝图、绳杆区别及其创建方法

绳索 是通过使用距离和弯曲约束将粒子连接起来而形成的。由于规则粒子没有方向(只有位置)&#xff0c;因此无法模拟扭转效应(维基百科)&#xff0c;绳子也无法保持其静止形状。然而&#xff0c;与杆不同的是&#xff0c;绳索可以被撕裂/劈开&#xff0c;并且可以在运行时改变其…

第3章 【例题】(完整版)

目录 前言 【例3.1】有关成绩结构体的例子 【例3.2】使用Score类的完整程序 【例 3.3】一个存在错误的程序 【例3.4】用对象赋值语句的例子 【例3.5】为类Score定义一个构造函数 【例3.6】建立对象的同时&#xff0c;用构造函数给数据成员赋初值 【例3.7】用成员初始…

智能手机2024:狂卷“微创新”后如何突破新机遇

文 | 智能相对论 作者 | 楷楷 2023年&#xff0c;智能手机市场终于开始展露曙光。Counterpoint Research数据显示&#xff0c;2023年10月全球智能手机销量同比增长5%&#xff0c;智能手机市场出货量在经历了连续27个月的同比下滑后&#xff0c;首次出现同比正增长。 特别是在…

IDEA卡在”正在解析Maven依赖项“的解决方法

修改Maven镜像&#xff0c;修改Maven镜像为阿里云镜像 1.文件路径 C:\Program Files\JetBrains\IntelliJ IDEA 2022.2.3\plugins 2.因为我使用的是InteliJ idea 自带的Maven&#xff0c;所以直接去idea 插件安装目录&#xff0c;找到Maven插件&#xff0c;找到setting.xml 文…

Linux第4步_安装VMwareTools

安装Ubuntu操作系统后&#xff0c;就可以安装VMwareTools了&#xff0c;目的是实现“电脑和虚拟机之间互相复制粘贴文件”。 1、双击桌面图标“VMware Workstation Pro”&#xff0c;然后点击下图中的“开机”&#xff0c;打开虚拟机电源。 2、双击下图中的用户名“zgq” 3、…

Ubuntu上使用node搭建本地静态http服务器

1.搭建步骤 1.安装Node.js。首先确保你的Ubuntu系统已经安装了Node.js。如果没有安装&#xff0c;可以通过以下命令进行安装&#xff1a; sudo apt-get update sudo apt-get install nodejs #安装nodejs 2.安装npm。npm是Node.js的包管理器&#xff0c;一般会随着Node.js一…

面试算法90:环形房屋偷盗

题目 一条环形街道上有若干房屋。输入一个数组表示该条街道上的房屋内财产的数量。如果这条街道上相邻的两幢房屋被盗就会自动触发报警系统。请计算小偷在这条街道上最多能偷取的财产的数量。例如&#xff0c;街道上5家的财产用数组[2&#xff0c;3&#xff0c;4&#xff0c;5…

【Filament】加载obj和fbx模型

1 前言 3D 模型的常用格式主要有 obj、fbx、gltf 等&#xff0c;Filament 中的 filamesh.exe 工具可以将 obj、fbx 格式转换为 filamesh 格式&#xff0c;然后再加载显示。对于 gltf 格式模型&#xff0c;可以通过 ModelViewer 加载显示&#xff0c;这不在本文的讨论范围内。 1…

【Java基础篇】常见的字符编码、以及它们的区别

常见的字符编码、以及它们的区别 ✔️ 解析✔️扩展知识仓✔️Unicode和UTF-8有啥关系?✔️有了UTF-8&#xff0c;为什么要出现GBK✔️为什么会出现乱码 ✔️ 解析 就像电报只能发出 ”滴” 和 ”答” 声一样&#xff0c;计算机只认识 0 和 1 两种字符&#xff0c;但是&#x…

Python从入门到网络爬虫(函数详解)

前言 函数是变成语言中最常见的语法&#xff0c;函数的本质就是功能的封装。使用函数可以大大提高编程效率与程序的可读性。函数是能够实现特定功能的计算机代码而已&#xff0c;他是一种特定的代码组结构。 函数的作用 1.提升代码的重复利用率&#xff0c;避免重复开发相同代…

ssm基于vue框架和elementui组件的手机官网论文

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本手机官网就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据信息&#x…

【UEFI基础】EDK网络框架(UNDI)

UNDI UNDI代码综述 UNDI全称Universal Network Driver Interface&#xff0c;它虽然属于UEFI网络框架的一部分&#xff0c;但是并没有在EDK开源代码中实现。不过目前主流网卡厂商都会提供UEFI下的网络驱动&#xff0c;并且大部分都实现了UNDI&#xff0c;这样BIOS下就可以通过…

鸿蒙APP上线注意事项

在将鸿蒙APP上线之前&#xff0c;开发者需要注意一些关键的事项&#xff0c;以确保应用的顺利发布和良好运营。以下是一些建议的注意事项&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 1.遵循应用市…

【常用排序算法】冒泡排序

冒泡排序 冒泡排序基本思想&#xff1a;N 个数的数组&#xff0c;经过N-1轮排序。 升序 大的值下沉&#xff0c;小的值上浮。降序 小的值下沉&#xff0c;小的字上浮 import java.util.Arrays; public class BubbleSort {public static void main(String[] args) {int[] values…

电脑视频需要分屏怎么做

在当今数字时代&#xff0c;人们对于视频的需求越来越高。有时候&#xff0c;我们可能想在同一屏幕上同时播放多个视频&#xff0c;进行对比、观看、剪辑或者其他目的。那么&#xff0c;视频分屏应该怎么做呢&#xff1f; 在本篇文章中&#xff0c;我们将会详细的为你介绍视频分…

Geotrust DV通配符证书保护域名数量

Geotrust是一家知名的SSL证书提供商&#xff0c;旗下有多种类型的SSL数字证书&#xff0c;保护网站数据在传输过程中的安全性和完整性&#xff0c;帮助用户确认其网站的安全。通配符SSL证书是Geotrust颁发的一种可以同时保护多个域名站点的SSL证书。今天就随SSL盾小编了解Geotr…

conda虚拟环境搭建和打包,删除,移动等全流程及相关问题汇总

私人笔记无偿分享&#xff0c;更多内容请访问&#xff1a;链接&#xff1a;https://pan.baidu.com/s/19mS5N9XJ_AotF20kUwSA3w?pwdp5kx 提取码&#xff1a;p5kx 复制这段内容后打开百度网盘手机App&#xff0c;操作更方便哦 4.4. anaconda虚拟环境搭建&#xff1a; 网址&am…

解决在test以外的目录下导入junit无效

以上引用来自src目录下的文件&#xff0c;可以看到&#xff0c;和junit有关的导入都飘红&#xff0c;但明明junit已经被正确导入进了项目中。 再看右侧的Maven的依赖下方&#xff0c;junit的右边有一个很不起眼的(test) 这是因为junit作为测试框架&#xff0c;可能包含仅适用于…

Halcon区域的面积和中心点area_center

Halcon区域的面积和中心点 提到区域的特征&#xff0c;最常用的莫过于区域的面积和中心点坐标信息。实际工作中&#xff0c;经常会使用面积或中心点进行特征的选择和定位。Halcon中的area_center算子就是用于实现这一功能的&#xff0c;该算子一次返回以下两个结果。 &#xf…

【KingbaseES】实现MySql函数WEEKS_BETWEEN

WEEKS_BETWEEN CREATE OR REPLACE FUNCTION weeks_between(start_date date, end_date date) RETURNS integer AS $$ BEGIN RETURN EXTRACT(WEEK FROM end_date) - EXTRACT(WEEK FROM start_date); END; $$ LANGUAGE plpgsql IMMUTABLE;结果展示