qt元对象系统之 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, "")
然后通过moc工具生成以下变量和函数的定义
静态对象 staticMetaObject
静态方法 qt_static_metacall
成员虚函数 metaObject, qt_meatacast, qt_metacall
例子
class Hello : public QObject
{
Q_OBJECT
};
moc生成的内容
QT_BEGIN_MOC_NAMESPACE
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
struct qt_meta_stringdata_Hello_t {
QByteArrayData data[1];
char stringdata0[6];
};
#define QT_MOC_LITERAL(idx, ofs, len) \
Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
qptrdiff(offsetof(qt_meta_stringdata_Hello_t, stringdata0) + ofs \
- idx * sizeof(QByteArrayData)) \
)
static const qt_meta_stringdata_Hello_t qt_meta_stringdata_Hello = {
{
QT_MOC_LITERAL(0, 0, 5) // "Hello" },
"Hello"
};
#undef QT_MOC_LITERAL static const uint qt_meta_data_Hello[] = { // content:
7, // revision
0, // classname
0, 0, // classinfo
0, 0, // methods
0, 0, // properties
0, 0, // enums/sets
0, 0, // constructors
0, // flags
0, // signalCount 0 // eod
}; void Hello::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
Q_UNUSED(_o);
Q_UNUSED(_id);
Q_UNUSED(_c);
Q_UNUSED(_a);
} const QMetaObject Hello::staticMetaObject = {
{ &QObject::staticMetaObject, qt_meta_stringdata_Hello.data,
qt_meta_data_Hello, qt_static_metacall, nullptr, nullptr}
}; const QMetaObject *Hello::metaObject() const
{
return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
} void *Hello::qt_metacast(const char *_clname)
{
if (!_clname) return nullptr;
if (!strcmp(_clname, qt_meta_stringdata_Hello.stringdata0))
return static_cast<void*>(this);
return QObject::qt_metacast(_clname);
} int Hello::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
_id = QObject::qt_metacall(_c, _id, _a);
return _id;
}
QT_WARNING_POP
QT_END_MOC_NAMESPACE
QT_MOC_LITERAL用来初始化QByteArrayData结构体,
struct Q_CORE_EXPORT QArrayData
{
QtPrivate::RefCount ref;
int size;
uint alloc : 31;
uint capacityReserved : 1; qptrdiff offset; // in bytes from beginning of header void *data()
{
Q_ASSERT(size == 0
|| offset < 0 || size_t(offset) >= sizeof(QArrayData));
return reinterpret_cast<char *>(this) + offset;
} ....
};
Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, offset)展开后是{ Q_REFCOUNT_INITIALIZE_STATIC, len, 0, 0, offset }
可以看到 QT_MOC_LITERAL(0, 0, 5) // "Hello"
代表Hello字符串长度5, 最终计算出的offset为字符串地址和用来定位Hello字符串地址所对应的QByteArrayData地址的偏移
注意: 这里只有一个Hello字符串,如果有n个字符串, QByteArrayData data[1]; 就会变成QByteArrayData data[n];
假如Hello字符串所对应的QByteArrayData为data[3], 那么 offset 就是 Hello地址与&data[3]的偏移
此后可以用该对应的QByteArrayData的data()方法取得Hello字符串
qt_meta_data_Hello的头部为这个结构体
struct QMetaObjectPrivate
{
// revision 7 is Qt 5.0 everything lower is not supported
enum { OutputRevision = 7 }; // Used by moc, qmetaobjectbuilder and qdbus int revision;
int className;
int classInfoCount, classInfoData;
int methodCount, methodData;
int propertyCount, propertyData;
int enumeratorCount, enumeratorData;
int constructorCount, constructorData;
int flags;
int signalCount;
....
}
0, 0, // methods如果定义了信号函数或者槽函数, 第二个0就会变成14, 而第一个0则变为信槽总数
注意: 信号函数也是由moc工具自动生成的,而0, // signalCount 中的0则变为信号函数总数
信号函数通常如下
// SIGNAL 0
void Hello::tellName(QString _t1)
{
void *_a[] = { nullptr, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
QMetaObject::activate(this, &staticMetaObject, 0, _a);
}
第三个参数是信号在本类中的本地信号索引, 最终会展开为此函数,
void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_index, void **argv)
其中signalOffset为计算出来的全部父类信号总数, 然后信号的绝对索引为 int signal_index = signalOffset + local_signal_index;
actiate函数的调用,导致所有连接上的槽函数被调用
qt元对象系统之 Q_OBJECT宏的更多相关文章
- Qt 元对象系统(Meta-Object System)(不管是否使用信号槽,都推荐使用)
Qt 元对象系统(Meta-Object System) Qt的元对象系统基于如下三件事情: 类:QObject,为所有需要利用原对象系统的对象提供了一个基类. 宏:Q_OBJECT,通常可以声明在类 ...
- Qt元对象系统简介
在Qt中提供了c++的扩展,提供了一种元对象系统的机制,(meta-object-system)的机制.其中包含了信号与槽的内部机制,能够访问到QObject子类的元对象信息的功能. Q_OBJECT ...
- Qt 元对象系统(Meta-Object System)
(转自:http://blog.csdn.net/aladdina/article/details/5496891) Qt的元对象系统基于如下三件事情: 类:QObject,为所有需要利用原对象系统的 ...
- 解析Qt元对象系统(四) 属性系统(确实比较方便)
官方解释 我们在Qt源码中可以看到一个QObject的子类经常会用到一些Q_开头的宏,例如QMainWindow类开始部分代码是这样的: Q_PROPERTY(QSize iconSize READ ...
- qt 元对象系统
元对象系统 Qt中的元对象系统是用来处理对象间通讯的信号/槽机制.运行时的类型信息和 动态属性系统. 它基于下列三类: QObject类: 类声明中的私有段中的Q_OBJECT宏: 元对象编译器(mo ...
- 解析Qt元对象系统(五) Q_INVOKABLE与invokeMethod(automatic connection从Qt4.8开始的解释已经与之前不同,发送对象驻足于哪一个线程并不重要,起到决定作用的是接收者对象所驻足的线程以及发射信号(该信号与接受者连接)的线程是不是在同一个线程)good
概述查看Qt源码可知,Q_INVOKABLE是个空宏,目的在于让moc识别. 使用Q_INVOKABLE来修饰成员函数,目的在于被修饰的成员函数能够被元对象系统所唤起. Q_INVOKABLE与QMe ...
- Qt笔记——元对象系统
Qt元对象系统提供了对象间的通信机制:信号和槽.以及执行类形信息和动态属性系统的支持.是标注C++的一个扩展,它使得Qt可以更好的实现GUI图形用户界面编程.Qt的元对象系统不支持C++模板.虽然模板 ...
- 深入了解Qt(二)之元对象系统(Meta-Object System)
深入了解Qt主要内容来源于Inside Qt系列,本文做了部分删改,以便于理解.在此向原作者表示感谢! 在Qt Meta Object System-元对象系统这篇文章中,从底层实现的源码剖析了元对象 ...
- Qt对象模型之二:对象树与元对象系统
一.对象树的概念 Qt中使用对象树(object tree)来组织和管理所有的QObject类及其子类的对象.当创建一个QObject时,如果使用了其他的对象作为其父对象(parent),那么这个 Q ...
- Qt元对象和属性系统详解
Qt 是一个用标准 C++ 编写的跨平台开发类库,它对标准 C++ 进行了扩展,引入了元对象系统.信号与槽.属性等特性,使应用程序的开发变得更高效. 本节将介绍 Qt 的这些核心特点,对于理解和编写高 ...
随机推荐
- 【iOS逆向】某茅台App算法分析还原
1.目标 某茅台软件的actParam算法分析还原. 2.使用工具 mac系统 frida-ios-dump:砸壳 已越狱iOS设备:脱壳及frida调试 IDA Pro:静态分析 Charles:抓 ...
- i春秋象棋
这是一道非常有意思的一道题,打开后就是一个pve的象棋游戏,我觉得下赢了就应该会出现flag,可惜多次尝试后失败了(果真有点厉害,我一时兴起就玩了好几把,有空试试拿更厉害的电脑跟他对下,如果赢了会怎么 ...
- 如何利用C++使Windows蓝屏
如何利用C++使Windows蓝屏 虽说windows非常强大,但是使它蓝屏也非常简单: 如果你想让Windows蓝屏,你一定会在运行框里输入: cmd /c for /f %I in ('wmic ...
- 关于python转义字符在正则匹配中的问题研究
问题 首先看一个问题: import re text = r"\学" print(text) zz = r"\学" result = re.findall(zz ...
- 处理get请求中文乱码tomcat请求
修改tomcat中server配置:添加 URIEncoding="UTF-8" <Connector port="8090" protocol=&quo ...
- Spring Boot整合log4j实战(一):排除自带依赖、日志重定向、测试类验证
〇.参考资料 1.springboot整合log4j全过程详解 https://blog.csdn.net/m0_60845963/article/details/123307232 2.Spring ...
- 【SQL查询】必会的常用函数:条件函数、日期函数、文本函数、窗口函数
〇.概述 1.内容 选择(双分支.多分支) 一.条件函数 1.计算25岁以上和以下的用户数量 CASE THEN END多分支选择 SELECT (CASE WHEN age>=25 THEN ...
- 【Java EE】Day11 BootStrap、响应式布局、栅格系统、CSS样式、案例
一.BootStrap介绍 https://v3.bootcss.com/css/#overview 1.概念 基于三剑客开发的前端开发框架 定义了许多css样式和js插件,从而得到丰富的页面效果 依 ...
- python装饰器初级
global与nonlocal 1.global的作用: 可以在局部空间里直接就该全局名称工具中的数据 代码展示: name = 'moon' #设置了一个全局变量 def fucn(): name ...
- os与sys模块,json模块
一.os模块(重要) os模块主要与操作系统打交道 1.创建目录(文件夹) import os os.mkdir(r'a1') # 在执行文件所在的路径下创建单级目录a1 os.mkdir(r'a2\ ...