Qt源码分析(一)

2023-05-16

欢迎加QQ群309798848交流C/C++/linux/Qt/音视频/OpenCV

源码面前,了无秘密。阅读源码能帮助我们理解实现原理,然后更灵活的运用。

接下来我用VS2015调试Qt5.9源码。

首先提一下,Qt在WinMain中调用用户的main函数:

我们知道,Qt的类以QObject为首,QWidget,QLabel之类的都是其子类(直接或间接继承)。

那么先来看看QObject的源码,我在下图打了个断点:

void debugQtSource()
{
    QObject* obj = new QObject;
    
}

F11进入,

QObject::QObject(QObject *parent)
    : d_ptr(new QObjectPrivate)
{
    Q_D(QObject);
    d_ptr->q_ptr = this;
    d->threadData = (parent && !parent->thread()) ? parent->d_func()->threadData : QThreadData::current();
    d->threadData->ref();
    if (parent) {
        QT_TRY {
            if (!check_parent_thread(parent, parent ? parent->d_func()->threadData : 0, d->threadData))
                parent = 0;
            setParent(parent);
        } QT_CATCH(...) {
            d->threadData->deref();
            QT_RETHROW;
        }
    }
#if QT_VERSION < 0x60000
    qt_addObject(this);
#endif
    if (Q_UNLIKELY(qtHookData[QHooks::AddQObject]))
        reinterpret_cast<QHooks::AddQObjectCallback>(qtHookData[QHooks::AddQObject])(this);
}

可以看到关键是d_ptr(d_pointer)

d_ptr声明:QScopedPointer<QObjectData> d_ptr;

QScopedPointer的思想是RAII,作用是用户不需要手动delete。

QObjectPrivate继承QObjectData

QObjectData定义:

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 deleteLaterCalled : 1;
    uint unused : 24;
    int postedEvents;
    QDynamicMetaObjectData *metaObject;
    QMetaObject *dynamicMetaObject() const;
};

QObjectData有一个指针q_ptr,指向QObject。

通过d_ptr(new QObjectPrivate);和d_ptr->q_ptr = this; 可以知道QObject和QObjectData都有一个指针互相指向对方。

接下来先看一个关系图:

    Qt实现采用了d-pointer这种方式。

使用d-pointer的目的:
实现二进制兼容,头文件与实现细节无关。Qt started out closed source?

二进制兼容:即Qt(dll)版本的更新替换不会影响应用程序exe。因为Qt的接口类(QObject等)的实例的大小是固定的。

在Qt中,QObject,QWidget,QLabel这些都是接口类,真正的实现在QObjectPrivate,QWidgetPrivate,QLabelPrivate 等Private类中。

QObjec的子类,例如QWidget,将QWidgetPrivate*传给QObject的d_ptr。同理QObjectData的子类,例如QWidgetPrivate将QWidget*传给QObjectData的q_ptr。也就是是说着两个类继承树中,各自维护一个指向对方的指针。

但是有一个问题,d_ptr是QObjectData*,我需要将他转为QWidgetPrivate*才能调用QWidgetPrivate的函数或数据。每次使用的时候都要转换指针很麻烦。考虑到代码复用,Qt采用了宏Q_D和Q_Q。

template <typename T> static inline T *qGetPtrHelper(T *ptr) { return ptr; }
template <typename Wrapper> 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<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 *>(qGetPtrHelper(Dptr)); } \
    inline const Class##Private* d_func() const { return reinterpret_cast<const Class##Private *>(qGetPtrHelper(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()

如上,Q_D将d_ptr从QObjectData*转换为QWidgetPrivate*,然后赋值给d

           Q_Q将q_ptr从QObject*转换为QWidget*,然后赋值给q

关于d-pointer

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Qt源码分析(一) 的相关文章

  • ffmpeg 源码分析 解码流程

    以ffmpeg 3 4 中的ffplay 来举例 全局初始化 av register all avformat network init AVFORMAT 设置过程 avformat alloc context avformat open
  • Qt源码分析(一)

    欢迎加QQ群309798848交流C C 43 43 linux Qt 音视频 OpenCV 源码面前 xff0c 了无秘密 阅读源码能帮助我们理解实现原理 xff0c 然后更灵活的运用 接下来我用VS2015调试Qt5 9源码 首先提一下
  • ArrayList源码分析

    ArrayList源码分析 注意 本笔记分析对象为 Java8 版本 随版本不同 源码会发生变化 1 ArrayList类图与简介 ArrayList是一个 非线程安全 基于数组实现的一个动态数组 可以看到 它的顶层接口是 Collecti
  • PX4源码分析12:怎样得到某个版本的PX4源码?(本文以v1.10.0为例)

    Get a Specific Release To get the source code for a specific older release 参考链接 xff1a https blog csdn net weixin 4186976
  • [gevent源码分析] 深度分析gevent运行流程

    一直对gevent运行流程比较模糊 xff0c 最近看源码略有所得 xff0c 不敢独享 xff0c 故分享之 gevent是一个高性能网络库 xff0c 底层是libevent xff0c 1 0版本之后是libev xff0c 核心是g
  • 【5G核心网】free5GC Path Switch Request源码分析

    Path Switch Request 过程的目的是请求将 NG U 传输承载的下行链路终结点切换到新的终结点 Figure 8 4 4 2 1 Path switch request successful operation NG RAN
  • 【containerd 源码分析】containerd image list 源码分析

    本文分析 containerd 列出所有镜像的分析过程 xff0c 包括 ctr image 命令行以及 containerd daemon 执行 过程 xff0c 也包含镜像 metadata xff0c content 等内容 1 执行
  • OVS Bond lacp源码分析

    近期项目中要使用Ovs bond接口 xff0c Ovs Bond 只有三种模式 xff1a balance tcp xff0c balance slb xff0c active backup 这三种模式的工作方式如下 xff1a 1 ac
  • Hadoop源码分析——JobClient

    1 MapReduce作业处理过程概述 当用户使用Hadoop的Mapreduce计算模型来进行处理问题时 xff0c 用户只需要定义所需的Mapper和Reduce处理函数 xff0c 还有可能包括的Combiner Comparator
  • Hadoop源码分析——计算模型MapReduce

    MapReduce 是一个计算模型 xff0c 也是一个处理和生成超大数据集的算法模型的相关实现 用户首先创建一个Map函数处理一个基于key value pair的数据集合 xff0c 输出中间的基于 key value pair 的数据
  • MAVROS 源码分析

    一 安装 MAVROS 利用机载计算机对 PX4 飞控进行 OFFBOARD 控制 xff0c 需要在机载计算机上安装 ROS 的 MAVROS 包 安装方式可以参考 PX4 开发者网站 xff0c 有二进制文件安装和源码安装两种方式 xf
  • Android 11 PackageManagerService源码分析(二):Packages.xml详解

    1 开篇 在上一篇文章中提到Settings类会在PackageManagerService启动过程中对packages xml等一些列xml文件进行解析 那么有以下问题 xff1a 这些文件记录了什么内容 xff1f 为什么需要这些文件
  • apache源码分析v2.0

    一 概要 1 平台功能层 xff0c 可移植运行库层 xff0c 核心功能层 xff0c 可选功能层 xff0c 第三方支持库 2 核心功能层 xff1a mod core 处理配置文件中的大部分配置指令 mod so 动态加载其余模块 m
  • Python之禅(The Zen of Python)源码分析

    简介 非常高兴大家能够订阅这个专栏 在这里我将会给大家分享一些Python相关源码的剖析 在接下来的这段日子里 我会一同带各位pythonista探索Python的奥秘 该从什么开始 思来想去 我觉得作为一个Python初学者还是Pytho
  • GTest源码剖析(六)——RUN_ALL_TESTS

    GTest源码剖析 RUN ALL TESTS GTest源码剖析RUN ALL TESTS RUN ALL TESTS源码分析 1 UnitTestRun 2 HandleExceptionsInMethodIfSupported 3 U
  • supervisor源码分析

    Supervisor分析 1 运行原理概述 Supervisor生成主进程并将主进程变成守护进程 supervisor依次生成配置文件中的工作进程 然后依次监控工作进程的工作状态 并且主进程负责与supervisorctl客户端通信 实现主
  • 【ClickHouse内核】资源管理

    目录 概述 资源使用追踪机制 MemoryTracker ProfileEvents QueryProfiler 举个例子 资源隔离机制 内存隔离 CPU隔离 IO隔离 资源使用配额 Quota 机制 结论 概述 资源管理对于数据库来说是非
  • Log4j2注入漏洞万字剖析-汇总收藏版(攻击步骤、漏洞原理、2.15.0-RC1绕过原理以及2.15.0、2.16.0修复原理)

    系列文章 2 15 0之前版漏洞相关文章 Log4j2注入漏洞 CVE 2021 44228 万字深度剖析 一 开篇与基础知识 Log4j2注入漏洞 CVE 2021 44228 万字深度剖析 二 漏洞原理 Log4j2注入漏洞 CVE 2
  • ARouter 之注解 @JvmField 和 @Autowired

    文章目录 1 定义 2 使用 3 源码分析 4 为什么 Autowired 要搭配 JvmFiled 同时使用 1 定义 在 Activity 进行数据传递一般都会通过 getIntent putxxx getxxx 方法 在 Fragme
  • IDEA国际化资源Key无法全局重命名的解决方案

    一 前言 最近在开发中使用到了HibernateValidator进行入参校验以及错误消息的国际化支持 大家应该都知道在使用HibernateValidator进行校验的时候 我们只需在需要在校验的变量上添加相应的注解 同时在message

随机推荐

  • dell 台式电脑设置每天定时开机和关机

    每天定时开机设置 xff1a 戴尔电脑通过CMOS设置实现自动开机的设置过程如下 xff1a 1 首先进入 CMOS SETUP 程序 大多数主板是在计算机启动时按DEL或F2键进入 xff1b 2 然后将光条移到 Power Manage
  • windows批处理自动获取电脑配置信息

    39 2 gt nul 3 gt nul amp cls amp 64 echo off 39 amp rem 获取本机系统及硬件配置信息 39 amp set 61 Any question amp set 64 61 WX amp se
  • Centos7搭建cisco ocserv

    一 安装的部分直接yum安装即可 yum y install ocserv 二 配置文件根据实际情况调整 auth方式有两种 1 系统账号认证 配置的话就是 xff1a auth 61 34 pam 34 2 本地文件认证 配置的话就是 x
  • 私有harbor部署(docker方式)

    环境准备 docker compose v Docker Compose version v2 14 2 wget https github com docker compose releases download v2 14 2 dock
  • ORACLE扩展表空间

    一 查询表空间使用情况 SELECT UPPER F TABLESPACE NAME 34 表空间名 34 D TOT GROOTTE MB 34 表空间大小 M 34 D TOT GROOTTE MB F TOTAL BYTES 34 已
  • Oracle 常用性能监控SQL语句

    1 查看表锁 SELECT FROM SYS V SQLAREA WHERE DISK READS gt 100 2 监控事例的等待 SELECT EVENT SUM DECODE WAIT TIME 0 0 1 34 Prev 34 SU
  • Nginx出现“ 413 (499 502 404) Request Entity Too Large”错误解决方法

    1 Nginx413错误的排查 修改上传文件大小限制 在使用上传POST一段数据时 xff0c 被提示413 Request Entity Too Large xff0c 应该是nginx限制了上传数据的大小 解决方法就是 打开nginx主
  • 查看弹出广告来自哪个软件

    打开VS的Spy 43 43 将指针移到广告处 xff0c 然后点OK xff0c 在Process标签页可以看到进程id和线程id将获得的16进制进程id xff08 例如 xff1a 000025F8 xff09 通过计算器转成10进制
  • C++多态虚函数实现原理,对象和虚函数表的内存布局

    基本概念 我们知道C 43 43 动态多态是用虚函数实现的 xff0c 而虚函数的实现方式虽说C 43 43 标准没有要求 xff0c 但是基本都是用虚函数表实现的 xff08 编译器决定 xff09 所以我们有必要了解一下虚函数表的实现原
  • C++ STL中递归锁与普通锁的区别

    在多线程编程中 xff0c 保护共享资源的访问很重要 xff0c 为了实现这个目标 xff0c C 43 43 标准库 xff08 STL xff09 中提供了多种锁 xff0c 如std mutex和std recursive mutex
  • VS+Qt开发环境

    VS Qt下载 VS下载 xff1a https visualstudio microsoft com zh hans vs Qt下载安装 xff1a https www bilibili com video BV1gx4y1M7cM VS
  • windows下使用ShiftMediaProject编译调试FFmpeg

    为什么要编译FFmpeg xff1f 定制模块调试源码 windows下编译 推荐项目ShiftMediaProject FFmpeg 平时总是看到一些人说windows下编译FFmpeg很麻烦 xff0c 这时候我就都是微微一笑 xff0
  • RTSP分析

    RTSP使用TCP来发送控制命令 xff08 OPTIONS DESCRIBE SETUP PLAY xff09 xff0c 因为TCP提供可靠有序的数据传输 xff0c 而且TCP还提供错误检测和纠正 RTSP的报文格式可以参考HTTP的
  • RTP分析

    参考 RTP xff08 A Transport Protocol for Real Time Applications 实时传输协议 xff0c rfc3550 xff09 RTP Payload Format for H 264 Vid
  • VS链接器工具错误 LNK2019:无法解析的外部符号

    常见的问题 以下是一些导致 LNK2019 的常见问题 xff1a 未链接的对象文件或包含符号定义的库 在 Visual Studio 中 xff0c 验证包含定义源代码文件是生成 xff0c 分别链接为项目的一部分 在命令行中 xff0c
  • FFmpeg合并视频流与音频流

    mux h ifndef MUX H define MUX H ifdef cplusplus extern 34 C 34 endif include 34 common h 34 include 34 encode h 34 typed
  • 解决电脑同时使用有线网上内网,无线网上外网的冲突

    由于内网有网络限制 xff08 限制娱乐等 xff09 xff0c 所以肯定要用外网 xff08 无线网卡 xff09 但是有的网站只能用内网访问 xff0c 比如gitlab xff0c oa等 我电脑刚开始连接了wifi后上不了gitl
  • Python斗鱼直播间自动发弹幕脚本

    工具 xff1a Python xff0c Chrome浏览器 因为不会用短信验证码登录 xff0c 所以使用QQ帐号登录 xff0c 必须要斗鱼帐号绑定QQ号 难点主要是帧的切换 查找元素可以通过chrome浏览器鼠标指向该元素 xff0
  • Qt+FFmpeg录屏录音

    欢迎加QQ群309798848交流C C 43 43 linux Qt 音视频 OpenCV 源码 xff1a Qt 43 FFmpeg录屏录音 NanaRecorder 之前的录屏项目ScreenCapture存在音视频同步问题 xff0
  • Qt源码分析(一)

    欢迎加QQ群309798848交流C C 43 43 linux Qt 音视频 OpenCV 源码面前 xff0c 了无秘密 阅读源码能帮助我们理解实现原理 xff0c 然后更灵活的运用 接下来我用VS2015调试Qt5 9源码 首先提一下