首页
社区
课程
招聘
[原创]QT信号槽简易分析_如何查看与分析QT的源码实现
发表于: 2019-3-19 00:25 8034

[原创]QT信号槽简易分析_如何查看与分析QT的源码实现

2019-3-19 00:25
8034

(课堂案例分享, 首次发帖, 若有错误与不足之处, 希望指正)

#include <QObject>

class CStudent : public QObject
{
  Q_OBJECT

public:
    CStudent(QObject *parent);
    ~CStudent();

    void SetAge(int nAge) {
      emit age(3, nAge);
    }

signals:
    void age(int n, double nAge);

public slots: 
    void OnAgedChange(int n, double nAge) {
        m_nAge = nAge;
    }

private:
    int m_nAge;
};
#define Q_OBJECT \
public: \
  QT_WARNING_PUSH \
  Q_OBJECT_NO_OVERRIDE_WARNING \  
  static const QMetaObject staticMetaObject; \
  virtual const QMetaObject *metaObject() const; \
  virtual void *qt_metacast(const char *); \
  virtual int qt_metacall(QMetaObject::Call, int, void **); \
  QT_TR_FUNCTIONS \
private: \
  Q_OBJECT_NO_ATTRIBUTES_WARNING \
  Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); \
  QT_WARNING_POP \
  struct QPrivateSignal {}; \
  QT_ANNOTATE_CLASS(qt_qobject, "")
  • qt_meta_stringdata_CStudent_t : 存储类的字符串相关信息
  • qt_meta_data_CStudent : 存储类中函数相关的信息
    1. 函数名在 qt_meta_stringdata_CStudent_t 中的存储编号
    2. 参数个数
    3. 该函数的具体声明在 qt_meta_data_CStudent 中的偏移量
  • staticMetaObject : 类信息的总和
  • qt_metacast : 返回类名称
  • qt_metacall : 函数调用
    • void **_a : 数组指针, 每个指针指向一个函数的地址
    • _c : 函数的实现类型
    • _id : 函数id, 判断是否实现 & 以何种方式实现该函数
  • void CStudent::age(int _t1, double _t2) : 信号的实现
  • metaObject : 判断静态/动态调用
  • void **_a : 数组指针, 每个指针指向一个函数的地址
  • _c : 函数的实现类型
  • _id : 函数id, 判断是否实现 & 以何种方式实现该函数
  • Q_OBJECT 宏
    #define Q_OBJECT \
    public: \
      QT_WARNING_PUSH \
      Q_OBJECT_NO_OVERRIDE_WARNING \  
      static const QMetaObject staticMetaObject; \
      virtual const QMetaObject *metaObject() const; \
      virtual void *qt_metacast(const char *); \
      virtual int qt_metacall(QMetaObject::Call, int, void **); \
      QT_TR_FUNCTIONS \
    private: \
      Q_OBJECT_NO_ATTRIBUTES_WARNING \
      Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); \
      QT_WARNING_POP \
      struct QPrivateSignal {}; \
      QT_ANNOTATE_CLASS(qt_qobject, "")
    
  • 实现流程:



  • 实现流程
  • 如何定位?
    在槽的实现位置下断点, F5运行至断点后通过下图左下角的栈回溯找到active的实现函数
  • 函数关键点分析
    1. 查找关联链表位置
    2. 调用关联链表中的槽函数
  1. 创建demo
  2. 配置环境, 加载静态库
  3. 修改demo, 分析moc文件
  4. 定位关键点, 分析关键函数
  1. Visual Studio 2015
  2. QT 5.11.2
  3. Source Insight
  1. QT版本配置 (Change QT version)
  2. 安装QT源码, 并在源目录中添加QT源码地址
  3. 在 工具 - 选项 中添加 pdb 文件目录
  4. 测试: F12点进代码中的宏 signals中, 可以得到以下界面, 则表示配置成功!
  1. Source Insight中创建新项目, 将项目名称改为QtSource
  2. 找到QT源码安装目录, 回车, 再加载安装目录中的所有文件
  3. 包含顶层文件和内部文件, 两个都选中
  4. 关闭窗口, 窗口右侧有文件, 则创建项目成功
  1. 函数名在 qt_meta_stringdata_CStudent_t 中的存储编号
  2. 参数个数
  3. 该函数的具体声明在 qt_meta_data_CStudent 中的偏移量
  1. 如何定位?
    方法一 : 在VS中进入单步调试模式, 在connect函数上下断点, F11跟进至connect函数中查看函数实现源码

    方法二 : 打开Source Insight, 打开QtSource工程, 在搜索栏中查询QObject.conncet, 得到函数实现的源码
  2. connect函数 : 判断并转化输入的数据, 将数据封装成QT库函数中可以接收的参数, 并调用Connection函数关联信号与槽
    • 实现流程:



  3. Connection函数 : 将信号槽的关联信息以哈希表的形式存储
    • 实现流程
  1. 查找关联链表位置
  2. 调用关联链表中的槽函数
  • 创建demo
  • 配置环境, 加载静态库
  • 修改demo, 分析moc文件
  • 定位关键点, 分析关键函数
  • Visual Studio 2015
  • QT 5.11.2
  • Source Insight
  • QT版本配置 (Change QT version)
  • 安装QT源码, 并在源目录中添加QT源码地址
  • 在 工具 - 选项 中添加 pdb 文件目录
  • 测试: F12点进代码中的宏 signals中, 可以得到以下界面, 则表示配置成功!

  • [培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

    最后于 2019-3-19 00:27 被埃斯艾克斯编辑 ,原因:
    收藏
    免费 4
    支持
    分享
    最新回复 (2)
    雪    币: 23080
    活跃值: (3432)
    能力值: (RANK:648 )
    在线值:
    发帖
    回帖
    粉丝
    2
    感谢分享
    2019-3-19 10:11
    0
    游客
    登录 | 注册 方可回帖
    返回
    //