当前位置: 首页 > news >正文

[Qt]解析moc文件

产生moc文件

moc文件是Qt的moc预处理器处理带QOBJECT宏的类是产生的文件。

分析

一个Qt创建的示例工程,加上一个按钮的信号和槽产生的moc文件如下
moc_widget.cpp

/****************************************************************************
** Meta object code from reading C++ file 'widget.h'
**
** Created by: The Qt Meta Object Compiler version 67 (Qt 5.9.8)
**
** WARNING! All changes made in this file will be lost!
*****************************************************************************/#include "../../untitled42/widget.h"
#include <QtCore/qbytearray.h>
#include <QtCore/qmetatype.h>
#if !defined(Q_MOC_OUTPUT_REVISION)
#error "The header file 'widget.h' doesn't include <QObject>."
#elif Q_MOC_OUTPUT_REVISION != 67
#error "This file was generated using the moc from 5.9.8. It"
#error "cannot be used with the include files from this version of Qt."
#error "(The moc has changed too much.)"
#endifQT_BEGIN_MOC_NAMESPACE
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
struct qt_meta_stringdata_Widget_t {QByteArrayData data[3];char stringdata0[13];
};
#define QT_MOC_LITERAL(idx, ofs, len) \Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \qptrdiff(offsetof(qt_meta_stringdata_Widget_t, stringdata0) + ofs \- idx * sizeof(QByteArrayData)) \)
static const qt_meta_stringdata_Widget_t qt_meta_stringdata_Widget = {{
QT_MOC_LITERAL(0, 0, 6), // "Widget"
QT_MOC_LITERAL(1, 7, 4), // "test"
QT_MOC_LITERAL(2, 12, 0) // ""},"Widget\0test\0"
};
#undef QT_MOC_LITERALstatic const uint qt_meta_data_Widget[] = {// content:7,       // revision0,       // classname0,    0, // classinfo1,   14, // methods0,    0, // properties0,    0, // enums/sets0,    0, // constructors0,       // flags0,       // signalCount// slots: name, argc, parameters, tag, flags1,    0,   19,    2, 0x08 /* Private */,// slots: parametersQMetaType::Void,0        // eod
};void Widget::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{if (_c == QMetaObject::InvokeMetaMethod) {Widget *_t = static_cast<Widget *>(_o);Q_UNUSED(_t)switch (_id) {case 0: _t->test(); break;default: ;}}Q_UNUSED(_a);
}const QMetaObject Widget::staticMetaObject = {{ &QWidget::staticMetaObject, qt_meta_stringdata_Widget.data,qt_meta_data_Widget,  qt_static_metacall, nullptr, nullptr}
};const QMetaObject *Widget::metaObject() const
{return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
}void *Widget::qt_metacast(const char *_clname)
{if (!_clname) return nullptr;if (!strcmp(_clname, qt_meta_stringdata_Widget.stringdata0))return static_cast<void*>(this);return QWidget::qt_metacast(_clname);
}int Widget::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{_id = QWidget::qt_metacall(_c, _id, _a);if (_id < 0)return _id;if (_c == QMetaObject::InvokeMetaMethod) {if (_id < 1)qt_static_metacall(this, _c, _id, _a);_id -= 1;} else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {if (_id < 1)*reinterpret_cast<int*>(_a[0]) = -1;_id -= 1;}return _id;
}
QT_WARNING_POP
QT_END_MOC_NAMESPACE
  1. 结构体
struct qt_meta_stringdata_Widget_t {QByteArrayData data[3];char stringdata0[13];
};

QByteArrayData 类并不是暴露给程序员的一个类,可以直接查看它的定义,有限的信息来看看不出来什么。还有char stringdata0[13]也不清除是干啥的
2. 宏

#define QT_MOC_LITERAL(idx, ofs, len) \Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \qptrdiff(offsetof(qt_meta_stringdata_Widget_t, stringdata0) + ofs \- idx * sizeof(QByteArrayData)) \)

这个宏函数的作用,主要是下面为了初始化一个 qt_meta_stringdata_Widget_t 结构体的变量
3. 静态结构体变量

static const qt_meta_stringdata_Widget_t qt_meta_stringdata_Widget = {{
QT_MOC_LITERAL(0, 0, 6), // "Widget"
QT_MOC_LITERAL(1, 7, 4), // "test"
QT_MOC_LITERAL(2, 12, 0) // ""},"Widget\0test\0"
};

就注释来看好像标识了一个函数 Widget类下的 test 函数,正好是链接信号的槽函数。
4. 数组

static const uint qt_meta_data_Widget[] = {// content:7,       // revision0,       // classname0,    0, // classinfo1,   14, // methods0,    0, // properties0,    0, // enums/sets0,    0, // constructors0,       // flags0,       // signalCount// slots: name, argc, parameters, tag, flags1,    0,   19,    2, 0x08 /* Private */,// slots: parametersQMetaType::Void,0        // eod
};

太抽象了看不出来是什么
5. 静态成员变量

const QMetaObject Widget::staticMetaObject = {{ &QWidget::staticMetaObject, qt_meta_stringdata_Widget.data,qt_meta_data_Widget,  qt_static_metacall, nullptr, nullptr}
};

这个就是元对象了,比较重要存储了一个运行时和类相关的信息或者操作之类的
6. 获取元对象的接口

const QMetaObject *Widget::metaObject() const
{return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
}
  1. 一个普通成员函数
void *Widget::qt_metacast(const char *_clname)
{if (!_clname) return nullptr;if (!strcmp(_clname, qt_meta_stringdata_Widget.stringdata0))return static_cast<void*>(this);return QWidget::qt_metacast(_clname);
}

看函数签名好像是根据类名获取类指针
8. 一个普通的成员函数

int Widget::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{_id = QWidget::qt_metacall(_c, _id, _a);if (_id < 0)return _id;if (_c == QMetaObject::InvokeMetaMethod) {if (_id < 1)qt_static_metacall(this, _c, _id, _a);_id -= 1;} else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {if (_id < 1)*reinterpret_cast<int*>(_a[0]) = -1;_id -= 1;}return _id;
}

有一点需要注意的是它先会调用 基类的 QWidget::qt_metacall 它的主要作用就是调用 qt_static_metacall
9. 一个普通的成员函数

void Widget::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{if (_c == QMetaObject::InvokeMetaMethod) {Widget *_t = static_cast<Widget *>(_o);Q_UNUSED(_t)switch (_id) {case 0: _t->test(); break;default: ;}}Q_UNUSED(_a);
}

这位函数更是重量级,根据传入的id调用对应的槽函数

自定义信号

加上自定义信号

signals:void numberToZero();
connect(this, &Widget::numberToZero, this, &Widget::test1);
void Widget::test()
{qDebug() << QStringLiteral("按钮点击了");m_number--;if(m_number == 0){emit numberToZero();}
}void Widget::test1()
{qDebug() << QStringLiteral("数字为零了");
}

moc文件新增

// SIGNAL 0
void Widget::numberToZero()
{QMetaObject::activate(this, &staticMetaObject, 0, nullptr);
}

可以看到moc文件新增了信号的实现,这也就是为什么我们在写信号时不需要写实现,就可以直接调用,并且不会出现找不到链接符号的问题。总体上来看 moc文件是对自己写的类的cpp文件的扩充

相关文章:

  • xshell7连接ubuntu18.04
  • CODEFORCES --- 630A. Again Twenty Five!
  • python 中的 collections 使用详解
  • 【C++11】右值引用 + 移动语义 + 完美转发(重点)
  • Vue - 你知道Vue组件之间是如何进行数据传递的吗
  • css伪类:last-child或:first-child不生效
  • 【数据库】MySQL数据库学习涵盖的多个方面
  • vue项目安装下载项目包,报错clear up some disk space and try again
  • python学习25:python中的元组(tuple)
  • 【C语言】——指针八:指针运算笔试题解析
  • 明日周刊-第5期
  • Unity框架,ET框架8.1版本的打包流程记录
  • Linux——gdb
  • 计算机毕业设计选题之基于SSM的旅游管理系统【源码+PPT+文档+包运行成功+部署讲解】
  • Nginx: proxy_set_header 与 add_header 区别
  • 【划重点】MySQL技术内幕:InnoDB存储引擎
  • codis proxy处理流程
  • create-react-app项目添加less配置
  • HTTP中的ETag在移动客户端的应用
  • LeetCode29.两数相除 JavaScript
  • Sass 快速入门教程
  • Vue官网教程学习过程中值得记录的一些事情
  • Yii源码解读-服务定位器(Service Locator)
  • 从@property说起(二)当我们写下@property (nonatomic, weak) id obj时,我们究竟写了什么...
  • 从重复到重用
  • 翻译--Thinking in React
  • 免费小说阅读小程序
  • 七牛云 DV OV EV SSL 证书上线,限时折扣低至 6.75 折!
  • 深入体验bash on windows,在windows上搭建原生的linux开发环境,酷!
  • 什么软件可以剪辑音乐?
  • 使用Envoy 作Sidecar Proxy的微服务模式-4.Prometheus的指标收集
  • 云大使推广中的常见热门问题
  • 主流的CSS水平和垂直居中技术大全
  • const的用法,特别是用在函数前面与后面的区别
  • Hibernate主键生成策略及选择
  • # 手柄编程_北通阿修罗3动手评:一款兼具功能、操控性的电竞手柄
  • #调用传感器数据_Flink使用函数之监控传感器温度上升提醒
  • #我与Java虚拟机的故事#连载04:一本让自己没面子的书
  • %3cscript放入php,跟bWAPP学WEB安全(PHP代码)--XSS跨站脚本攻击
  • (01)ORB-SLAM2源码无死角解析-(56) 闭环线程→计算Sim3:理论推导(1)求解s,t
  • (10)工业界推荐系统-小红书推荐场景及内部实践【排序模型的特征】
  • (cos^2 X)的定积分,求积分 ∫sin^2(x) dx
  • (c语言版)滑动窗口 给定一个字符串,只包含字母和数字,按要求找出字符串中的最长(连续)子串的长度
  • (Git) gitignore基础使用
  • (初研) Sentence-embedding fine-tune notebook
  • (二)JAVA使用POI操作excel
  • (附源码)ssm考生评分系统 毕业设计 071114
  • (黑马出品_高级篇_01)SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式
  • (十三)Flask之特殊装饰器详解
  • (四)Android布局类型(线性布局LinearLayout)
  • (未解决)jmeter报错之“请在微信客户端打开链接”
  • (转)jdk与jre的区别
  • (转)大型网站的系统架构
  • (转)负载均衡,回话保持,cookie
  • (转)淘淘商城系列——使用Spring来管理Redis单机版和集群版