读QT5.7源码(七)QObjectData 和 QObjectPrivate

2023-11-12

在QObject中定义了一个保护权限的成员变量 d_ptr
protected:
    QScopedPointer<QObjectData> d_ptr;


QScopePointer<> 是一个模板类,维护特定类型的指针,这里d_ptr  相当于一个QObjectData对象的指针。

QObject 几乎是所有QT中的类的基类,因此QT中每个继承于Qobject的类都有这个指针,指向一个动态分配的QObjectData对象。


QObjectData类的定义


class Q_CORE_EXPORT QObjectData {
public:
    virtual ~QObjectData() = 0;
    QObject *q_ptr;    对象this指针
    QObject *parent;   父对象指针
    QObjectList children;       typedef QList<QObject*> QObjectList;     这个是对象的子对象链表,区别于父类和子类

    uint isWidget : 1;   是否是Wideget类型
    uint blockSig : 1;      是否处于信号阻塞
    uint wasDeleted : 1;     防止多次delete对象
    uint isDeletingChildren : 1;   是否在delete子对象
    uint sendChildEvents : 1;       是否向父对象报告对象插入和删除事件  应该为true
    uint receiveChildEvents : 1;     是否接收子对象的事件消息    应该为ture
    uint isWindow : 1; //for QWindow
    uint unused : 25;
    int postedEvents;
    QDynamicMetaObjectData *metaObject;
    QMetaObject *dynamicMetaObject() const;
};



在QObject的构造函数中对d_ptr进行了初始化


QObject::QObject(QObject *parent)
    : d_ptr(new QObjectPrivate)     这里是构建了一个QObjectPrivate对象,并将其指针赋给d_ptr
{
....................................省略
}


QObjectPrivate  是QObjectData的子类,这样就合情合理了。 事实上这个类是如此的重要,也是信息量很大的一个结构


class Q_CORE_EXPORT QObjectPrivate : public QObjectData
{
    Q_DECLARE_PUBLIC(QObject)

public:
    struct ExtraData
    {
        ExtraData() {}
    #ifndef QT_NO_USERDATA
        QVector<QObjectUserData *> userData;
    #endif
        QList<QByteArray> propertyNames;
        QVector<QVariant> propertyValues;
        QVector<int> runningTimers;
        QList<QPointer<QObject> > eventFilters;
        QString objectName;
    };                              //一些结构分别用来存放对象所属类的 property 运行时间等信息

    typedef void (*StaticMetaCallFunction)(QObject *, QMetaObject::Call, int, void **);
    struct Connection    //重要的结构   保存每个信号和槽的连接
    {
        QObject *sender;    发送对象的指针
        QObject *receiver;   接受对象的指针
        union {
            StaticMetaCallFunction callFunction;         接受对象的qt_static_metacall函数的指针
            QtPrivate::QSlotObjectBase *slotObj;
        };
        // The next pointer for the singly-linked ConnectionList
        Connection *nextConnectionList;   
        //senders linked list
        Connection *next;
        Connection **prev;
        QAtomicPointer<const int> argumentTypes;     参数值数组指针
        QAtomicInt ref_;
        ushort method_offset;    
        ushort method_relative;   
        uint signal_index : 27; // In signal range (see QObjectPrivate::signalIndex())
        ushort connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking
        ushort isSlotObject : 1;
        ushort ownArgumentTypes : 1;
        Connection() : nextConnectionList(0), ref_(2), ownArgumentTypes(true) {
            //ref_ is 2 for the use in the internal lists, and for the use in QMetaObject::Connection
        }
        ~Connection();
        int method() const { Q_ASSERT(!isSlotObject); return method_offset + method_relative; }
        void ref() { ref_.ref(); }
        void deref() {
            if (!ref_.deref()) {
                Q_ASSERT(!receiver);
                delete this;
            }
        }
    };
    // ConnectionList is a singly-linked list   信号对应的槽链表,每一个信号对应一个该结构,每一个连接保存在一个connection
    struct ConnectionList {
        ConnectionList() : first(0), last(0) {}
        Connection *first;
        Connection *last;
    };

    struct Sender   
    {
        QObject *sender;
        int signal;
        int ref;
    };


    QObjectPrivate(int version = QObjectPrivateVersion);
    virtual ~QObjectPrivate();
    void deleteChildren();

    void setParent_helper(QObject *);
    void moveToThread_helper();
    void setThreadData_helper(QThreadData *currentData, QThreadData *targetData);
    void _q_reregisterTimers(void *pointer);

    bool isSender(const QObject *receiver, const char *signal) const;
    QObjectList receiverList(const char *signal) const;
    QObjectList senderList() const;

    void addConnection(int signal, Connection *c);
    void cleanConnectionLists();

    static inline Sender *setCurrentSender(QObject *receiver,
                                    Sender *sender);
    static inline void resetCurrentSender(QObject *receiver,
                                   Sender *currentSender,
                                   Sender *previousSender);

    static QObjectPrivate *get(QObject *o) {
        return o->d_func();
    }

    int signalIndex(const char *signalName, const QMetaObject **meta = 0) const;
    inline bool isSignalConnected(uint signalIdx, bool checkDeclarative = true) const;
    inline bool isDeclarativeSignalConnected(uint signalIdx) const;

    // To allow abitrary objects to call connectNotify()/disconnectNotify() without making
    // the API public in QObject. This is used by QQmlNotifierEndpoint.
    inline void connectNotify(const QMetaMethod &signal);
    inline void disconnectNotify(const QMetaMethod &signal);

    template <typename Func1, typename Func2>
    static inline QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
                                                  const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot,
                                                  Qt::ConnectionType type = Qt::AutoConnection);

    template <typename Func1, typename Func2>
    static inline bool disconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
                                  const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot);

    static QMetaObject::Connection connectImpl(const QObject *sender, int signal_index,
                                               const QObject *receiver, void **slot,
                                               QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type,
                                               const int *types, const QMetaObject *senderMetaObject);
    static QMetaObject::Connection connect(const QObject *sender, int signal_index, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type);
    static bool disconnect(const QObject *sender, int signal_index, void **slot);
public:
    ExtraData *extraData;    // extra data set by the user
    QThreadData *threadData; // id of the thread that owns the object

    QObjectConnectionListVector *connectionLists;

    Connection *senders;     // linked list of connections connected to this object
    Sender *currentSender;   // object currently activating the object
    mutable quint32 connectedSignals[2];

    union {
        QObject *currentChildBeingDeleted;
        QAbstractDeclarativeData *declarativeData; //extra data used by the declarative module
    };

    // these objects are all used to indicate that a QObject was deleted
    // plus QPointer, which keeps a separate list
    QAtomicPointer<QtSharedPointer::ExternalRefCountData> sharedRefcount;
};

其中 QObjectConnectionListVector *connectionLists    是一个QVector<QObjectPrivate::ConnectionList>



class QObjectConnectionListVector : public QVector<QObjectPrivate::ConnectionList>
{
public:
    bool orphaned; //the QObject owner of this vector has been destroyed while the vector was inUse
    bool dirty; //some Connection have been disconnected (their receiver is 0) but not removed from the list yet
    int inUse; //number of functions that are currently accessing this object or its connections
    QObjectPrivate::ConnectionList allsignals;

    QObjectConnectionListVector()
        : QVector<QObjectPrivate::ConnectionList>(), orphaned(false), dirty(false), inUse(0)
    { }

    QObjectPrivate::ConnectionList &operator[](int at)
    {
        if (at < 0)
            return allsignals;
        return QVector<QObjectPrivate::ConnectionList>::operator[](at);
    }
};



结构图如下






1、QObjectList QObjectPrivate::receiverList(const char *signal) const    返回指定信号关联的接受对象的列表

QObjectList QObjectPrivate::receiverList(const char *signal) const
{
    Q_Q(const QObject);
    QObjectList returnValue;
    int signal_index = signalIndex(signal);   返回绝对索引
    if (signal_index < 0)
        return returnValue;
    QMutexLocker locker(signalSlotLock(q));
    if (connectionLists) {
        if (signal_index < connectionLists->count()) {
            const QObjectPrivate::Connection *c = connectionLists->at(signal_index).first;  根据索引在QVector中找到对应的ConnectionList,first指向表头

            while (c) {
                if (c->receiver)
                    returnValue << c->receiver;
                c = c->nextConnectionList;    遍历这个单项链表,将receiver不为空的添加到QObjectList
            }
        }
    }
    return returnValue;
}


2、QObjectList QObjectPrivate::senderList() const   返回链接到改对象的  对象列表


QObjectList QObjectPrivate::senderList() const
{
    QObjectList returnValue;
    QMutexLocker locker(signalSlotLock(q_func()));
    for (Connection *c = senders; c; c = c->next)
        returnValue << c->sender;                       通过遍历senders
    return returnValue;
}

3、int QObjectPrivate:: signalIndex  const char *signalName,const QMetaObject **meta) const      返回信号的绝对索引


int QObjectPrivate::signalIndex(const char *signalName,
                                const QMetaObject **meta) const
{
    Q_Q(const QObject);  //宏 q=this
    const QMetaObject *base = q->metaObject();
    Q_ASSERT(QMetaObjectPrivate::get(base)->revision >= 7);
    QArgumentTypeArray types;
    QByteArray name = QMetaObjectPrivate::decodeMethodSignature(signalName, types);  
    int relative_index = QMetaObjectPrivate::indexOfSignalRelative(
            &base, name, types.size(), types.constData());
    if (relative_index < 0)
        return relative_index;
    relative_index = QMetaObjectPrivate::originalClone(base, relative_index);
    if (meta)
        *meta = base;
    return relative_index + QMetaObjectPrivate::signalOffset(base);     +offset   返回绝对索引    索引相对于全部的信号包括继承来的
}



4、void QObjectPrivate:: addConnection (int signal, Connection *c)    将某个信号关联的Connection  加到链表中

void QObjectPrivate::addConnection(int signal, Connection *c)
{
    Q_ASSERT(c->sender == q_ptr);
    if (!connectionLists)
        connectionLists = new QObjectConnectionListVector();   如果容器为空创建它
    if (signal >= connectionLists->count())
        connectionLists->resize(signal + 1);                 根据信号的索引,如果容器对应的索引位置为空,表示还没有为信号连接任何函数,调整容器大小,
                                                              在对应的位置构建信号关联的ConnectionList
    ConnectionList &connectionList = (*connectionLists)[signal];
    if (connectionList.last) {
        connectionList.last->nextConnectionList = c;
    } else {
        connectionList.first = c;   
    }
    connectionList.last = c;      //.last始终指向最后加入的connection

    cleanConnectionLists();

    c->prev = &(QObjectPrivate::get(c->receiver)->senders);
    c->next = *c->prev;
    *c->prev = c;                               //加到接收对象的senders的链表里
    if (c->next)
        c->next->prev = &c->next;

    if (signal < 0) {
        connectedSignals[0] = connectedSignals[1] = ~0;
    } else if (signal < (int)sizeof(connectedSignals) * 8) {
        connectedSignals[signal >> 5] |= (1 << (signal & 0x1f));
    }
}





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

读QT5.7源码(七)QObjectData 和 QObjectPrivate 的相关文章

  • 如何在模型更改时停止ListView“跳跃”

    我需要做什么 我需要创建一个聊天窗口用一个ListView在 QML 中存储聊天消息 我设置listView positionViewAtEnd 以便跟踪最后的消息 我禁用positionViewAtEnd当我向上滚动时 我可以阅读过去的消
  • 如何在带有预编译头的项目中使用google protobuf

    我有一个包含多个项目的解决方案 我的项目 但不是全部 使用预编译头 我决定使用 protobuf 但遇到了一个问题 在 protoc exe 从 proto 生成 pb h 后 我尝试包含标头并收到错误 预编译标头未包含在 pb h 中 我
  • 加权 Voronoi 的 CGAL 2D APOLLONIUS 图 - 如何生成和获取面和顶点?

    我正在尝试根据阿波罗尼乌斯图生成加权沃罗诺伊 我正在使用 CGAL 库 我找不到如何从 apollonius 获取面和顶点的好例子 我有以下类型定义 typedef double NT typedef CGAL Cartesian lt N
  • 在 Qt5 中,是否需要 Q_INVOKABLE 来从 QML 调用公共 QObject 函数?

    我刚刚意识到我可以调用暴露于 QML 的对象的几乎任何函数 现在我对 Q INVOKABLE 很好奇 Qt5docs http doc qt io qt 5 qtqml cppintegration exposecppattributes
  • Qt 文件对话框默认后缀不起作用

    我将以下代码用于 QtQuick Dialogs 1 3 和 Qt 5 10 0 下 filedialog 的新属性 我使用 Qt Creator 5 10 默认套件构建它 import QtQuick 2 10 import QtQuic
  • 使用 Visual Studio 2013 构建 Qt 5.2.1 的静态版本

    几天来我一直在尝试使用 Visual Studio 2013 构建 Qt 的静态版本 我就是不明白我做错了什么 System Windows 7 64 位 Visual Studio 2013 仍安装 Visual Studio 2012
  • 如何在 QTabWidget Qt 中展开选项卡

    我有一个QTabWidget像这个 但我想展开选项卡以 填充 整个小部件宽度 如下所示 我怎样才能做到这一点 我在用Qt 5 3 2 and Qt 创建者 3 2 1 Update 我尝试使用setExpanding功能 ui gt myT
  • 退出 Qt 程序的正确方法?

    我应该如何退出 Qt 程序 例如在加载数据文件时 发现文件损坏 并且用户需要退出该应用程序或重新启动数据文件 我是不是该 call exit EXIT FAILURE call QApplication quit call QCoreApp
  • 使用 QtWebEngine 将 C++ 对象暴露给 Qt 中的 Javascript

    使用 QtWebkit 可以通过以下方式将 C 对象公开给 JavascriptQWebFrame addToJavaScriptWindowObject如中所述https stackoverflow com a 20685002 5959
  • PyQt5:如何使QThread返回数据到主线程

    I am a PyQt 5 4 1 1初学者 我的Python是3 4 3 这是我尝试遵循的many https mayaposch wordpress com 2011 11 01 how to really truly use qthr
  • Qt:如何连接到 SQLite?

    我安装了 SQLite3 解压到 c sqlite 创建了一个数据库 c sqlite mzsales 现在我试图在 QTableView 中显示其内容 QSqlDatabase db QSqlDatabase addDatabase QS
  • Qt - 设置不可编辑的QComboBox的显示文本

    我想将 QComboBox 的文本设置为某些自定义文本 不在 QComboBox 的列表中 而不将此文本添加为 QComboBox 的项目 此行为可以在可编辑的 QComboBox 上实现QComboBox setEditText cons
  • Qt - 获取互联网上托管的网页的源代码(HTML 代码)

    我想获取网页的源代码 HTML 例如StackOverflow的主页 这是我到目前为止编写的代码 QNetworkAccessManager manager QNetworkReply response manager get QNetwo
  • 如何消除 QTableWidget 中的空白?

    How do I get rid of the whitespace in my application 我想摆脱 QTableWidget 中的空白 蓝色箭头 我该怎么做 这是我的应用程序的代码 gridLayout QGridLayou
  • 使用 PyQt 和 matplotlib 在可滚动小部件中显示多个绘图

    由于我没有得到答案this https stackoverflow com questions 12179893 creating a scrollable multiplot with pythons pylab我尝试用 PyQt 解决这
  • 扩展 TabViewStyle styleData

    我目前正在尝试找到一种更好的方法来执行此操作 将图标添加到选项卡 现在 我正在放弃 styleData title 以包含图标源 但如果能够扩展 styleData 就更好了 这样我就可以包含其他自定义属性 这是我当前的黑客 Tab tit
  • 面向 Delphi 开发人员的 Qt

    有人知道为 Delphi C Builder VCL 开发人员解释 Qt 的书籍或教程吗 对于具有该背景的开发人员来说 学习 Qt 的最佳方法是什么 我对如何使用 Qt 完成我知道如何在 Delphi 中完成的事情特别感兴趣 例如 Qt 相
  • 如何将枚举类传递给 QML?

    我正在学习QML with Qt并在通过时遇到一些麻烦enum class to qml 当我使用信号时int参数 一切正常 代码运行完美 But 麻烦就在这里 如果我使用信号与一些enum class我有参数undefinedqml 信号
  • Qt 图表和数据可视化小部件

    我已经安装了 Qt 5 7 来尝试 Qt 图表和 Qt 数据可视化 但我在 Qt Designer 和 Qt Creator 中都找不到新的小部件 有什么建议我应该做什么才能让新的小部件出现在设计器中 我今天遇到了完全相同的问题 默认情况下
  • wkhtmltopdf 修补了 qt 吗?

    我正在尝试将多个 URL 转换为 PDF 但是 当我编译 wkhtmltopdf 或运行时apt get install wkhtmltopdf并尝试一下 它说 错误 此版本的 wkhtmltopdf 是针对未修补的 QT 版本构建的 并且

随机推荐

  • 使用Jenkins配置自动化构建

    原文地址 http blog csdn net littlechang article details 8642149 下载jenkins http mirrors jenkins ci org war 列出了jenkins的所有relea
  • C语言之完数、素数、回文数合集

    1 完全数 Perfect number 又称完美数或完备数 是一些特殊的自然数 它所有的真因子 即除了自身以外的约数 的和 即因子函数 恰好等于它本身 如果一个数恰好等于它的因子之和 则称该数为 完全数 第一个完全数是6 第二个完全数是2
  • MATLAB中定义数组序列,matlab怎么定义一个数组

    A n input n 数组的长度 for i 1 n fprintf a 0f i x input 分别输入各个数的值 A A x end A 就可以得到长度为n的数组了 建议在一开始就定义数组大小 这样可以减少内存的使用 同时加快计算速
  • List of default Mac OS X command-line editing bash keyboard shortcuts

    本文转载至 https maymay net blog 2007 07 18 list of default mac os x command line editing bash keyboard shortcuts More and mo
  • aspose 转pdf表格大小乱了_C#使用 aspose 从excel转成pdf,用矩阵处理其中的签章图片大小和位置...

    实例简介 C 使用 aspose 从excel转成pdf 用矩阵处理其中的签章图片大小和位置 实例截图 核心代码 public Stream ExcelToPdf Stream sm excel Stream sm Re new Memor
  • 16.网络爬虫—字体反爬(实战演示)

    网络爬虫 字体反爬 一 字体反爬原理 二 字体反爬模块Fonttools TTF文件 三 FontCreator 14 0 0 2790 FontCreatorPortable下载与安装 四 实战演示 五 后记 前言 个人简介 以山河作礼
  • LLVM查缺补漏-2

    Mailing Lists 邮件列表有两种基本形式 公告型 邮件列表 通常由一个管理者向小组中的所有成员发送信息 如电子杂志 新闻邮件等 讨论型 讨论组 所有的成员都可以向组内的其他成员发送信息 其操作过程简单来说就是发一个邮件到小组的公共
  • Java-接口

    Java 接口 1 概念 接口和类是平级的关系 举例以下 学习就是一个接口 可以飞 攻击性都是接口 2 接口的使用 接口使用interface关键词来定义 定义接口的结构 JDK1 7及以前 只能全局常量和抽象方法 全局常量 public
  • 用Groovy写Servlet

    本文参考自Servlet support 大部分代码引用了原文档 快速开始 Groovy语言提供了一个模块 可以让我们写用Groovy脚本的方式来编写Servlet 这叫做Groovlets 先看看一个简单的例子吧 下面这几个例子都来自官方
  • webpack&vite

    webpack支持多模块化 可以跑在服务端 一开始就要同一模块化代码 所以他需要把所有依赖读取一遍 并且转化为对应的代码 然后再去开启开发服务器 ast抽象语法分析工具 分析你写的文件有啥导入导出 vite只支持es module 只跑在浏
  • 五个温度带的分界线_中国划分为哪五个个温度带

    展开全部 在我国 从北到南习惯上划分为寒温带 中温带 暖温62616964757a686964616fe59b9ee7ad9431333366303732带 亚热带 热带 1 秦岭淮河线以南 主要是我国的亚热带和热带地区 一般亚热带位于温带
  • qt编写的简单日历控件lan2calendar

    使用中的一些bug可以反馈一下 项目地址 https gitee com mengtianwxs lan2calendar
  • 论文笔记:Autoregressive Tensor Factorizationfor Spatio-temporal Predictions

    0 摘要 张量因子tensor factorization分解方法在时空数据分析领域很受欢迎 因为它们能够处理多种类型的时空数据 处理缺失值 并提供计算效率高的参数估计程序 然而 现有的张量因子分解方法并没有尝试学习空间自相关 这些方法使用
  • snprintf函数和sprintf函数

    今天写代码 做字符串处理 写了以下语句 snprintf loginTime sizeof loginTime s s loginTime blankSpace 然后loginTime中的字符串老不对 记得以前用sprintf的时候 类似语
  • CISCN部分WP-ukfc

    WP ukfc 讲个笑话 华北19进不了决赛 再讲个笑话 27号黑灯 国粹过了300出头 努什么力 不如去海鲜市场 Web unzip L zip bello var www html R zip bello bello php 先传入L文
  • 51单片机在中断响应时,系统不能自动清除哪些中断请求标志?编程时应如何处理?...

    51单片机在中断响应时 系统不会自动清除中断请求标志 因此 程序员需要在编写的中断服务程序中手动清除相应的中断请求标志 这可以通过使用汇编指令或 C 语言函数来实现 在汇编语言中 可以使用 CLR bit 指令来清除某一位 在 C 语言中
  • linux中$0、$?、$*、$@、$#、$$

    0 shell脚本名 1 执行shell脚本传的第一个参数 n 第n个参数 上一条命令的执行状态 0为成功 执行shell脚本传的所有参数 同上 所在命令的PID test sh bin sh echo hello echo filenam
  • 接口测试全流程总结

    接口测试全流程扫盲 接口测试全流程扫盲 扫盲内容 1 什么是接口 2 接口都有哪些类型 3 接口的本质是什么 4 什么是接口测试 5 问什么要做接口测试 6 怎样做接口测试 7 接口测测试点是什么 8 接口测试都要掌握哪些知识 9 其他相关
  • 二进制补码的理解

    正数的原码 反码 补码 负数的原码 反码 补码关系为 原码 正数的原码符号位变为1 反码 正数的原码取反 补码 正数的原码取反加1 补码主要为了计算机进行减法运算 参考1 https www cnblogs com guanjianzhuo
  • 读QT5.7源码(七)QObjectData 和 QObjectPrivate

    在QObject中定义了一个保护权限的成员变量 d ptr protected QScopedPointer