宏展开是这样

#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宏的更多相关文章

  1. Qt 元对象系统(Meta-Object System)(不管是否使用信号槽,都推荐使用)

    Qt 元对象系统(Meta-Object System) Qt的元对象系统基于如下三件事情: 类:QObject,为所有需要利用原对象系统的对象提供了一个基类. 宏:Q_OBJECT,通常可以声明在类 ...

  2. Qt元对象系统简介

    在Qt中提供了c++的扩展,提供了一种元对象系统的机制,(meta-object-system)的机制.其中包含了信号与槽的内部机制,能够访问到QObject子类的元对象信息的功能. Q_OBJECT ...

  3. Qt 元对象系统(Meta-Object System)

    (转自:http://blog.csdn.net/aladdina/article/details/5496891) Qt的元对象系统基于如下三件事情: 类:QObject,为所有需要利用原对象系统的 ...

  4. 解析Qt元对象系统(四) 属性系统(确实比较方便)

    官方解释 我们在Qt源码中可以看到一个QObject的子类经常会用到一些Q_开头的宏,例如QMainWindow类开始部分代码是这样的: Q_PROPERTY(QSize iconSize READ ...

  5. qt 元对象系统

    元对象系统 Qt中的元对象系统是用来处理对象间通讯的信号/槽机制.运行时的类型信息和 动态属性系统. 它基于下列三类: QObject类: 类声明中的私有段中的Q_OBJECT宏: 元对象编译器(mo ...

  6. 解析Qt元对象系统(五) Q_INVOKABLE与invokeMethod(automatic connection从Qt4.8开始的解释已经与之前不同,发送对象驻足于哪一个线程并不重要,起到决定作用的是接收者对象所驻足的线程以及发射信号(该信号与接受者连接)的线程是不是在同一个线程)good

    概述查看Qt源码可知,Q_INVOKABLE是个空宏,目的在于让moc识别. 使用Q_INVOKABLE来修饰成员函数,目的在于被修饰的成员函数能够被元对象系统所唤起. Q_INVOKABLE与QMe ...

  7. Qt笔记——元对象系统

    Qt元对象系统提供了对象间的通信机制:信号和槽.以及执行类形信息和动态属性系统的支持.是标注C++的一个扩展,它使得Qt可以更好的实现GUI图形用户界面编程.Qt的元对象系统不支持C++模板.虽然模板 ...

  8. 深入了解Qt(二)之元对象系统(Meta-Object System)

    深入了解Qt主要内容来源于Inside Qt系列,本文做了部分删改,以便于理解.在此向原作者表示感谢! 在Qt Meta Object System-元对象系统这篇文章中,从底层实现的源码剖析了元对象 ...

  9. Qt对象模型之二:对象树与元对象系统

    一.对象树的概念 Qt中使用对象树(object tree)来组织和管理所有的QObject类及其子类的对象.当创建一个QObject时,如果使用了其他的对象作为其父对象(parent),那么这个 Q ...

  10. Qt元对象和属性系统详解

    Qt 是一个用标准 C++ 编写的跨平台开发类库,它对标准 C++ 进行了扩展,引入了元对象系统.信号与槽.属性等特性,使应用程序的开发变得更高效. 本节将介绍 Qt 的这些核心特点,对于理解和编写高 ...

随机推荐

  1. 记录下批处理bat脚本获取打包发布问题

    最近做了个Jenkins配合Gitlab自动部署Java项目到Windows Server服务器. Jenkins和Gitlab在Linux下,好一顿折腾,先记录下脚本,其余后续补充吧. 把Java项 ...

  2. c#winfrom通讯录管理系统

    一个简单的通讯录管理系统,适合毕业设计. 主要实现以下功能 1.系统登录 2.增加联系人 3.修改和删除联系人 4.查找联系人 5.系统用户管理 首先先搭建数据库. 我这边使用的版本是sqlserve ...

  3. SSH(五)spring整合hibernate

    一.创建hibernate实体映射文件. 在实体所在包创建映射文件product.hbm.xml,引入hibernate的映射约束.(该约束位于hibernate3.jar里面hibernate-ma ...

  4. 【Spark】Day01-入门、模块组成、4种运行模式详解及配置、案例实操(spark分析过程)

    一.概述 1.概念 基于内存的大数据分析计算引擎 2.特点 快速.通用.可融合性 3.Spark内置模块[腾讯8000台spark集群] Spark运行在集群管理器(Cluster Manager)上 ...

  5. python自然语言处理(NLP)1------中文分词1,基于规则的中文分词方法

    python中文分词方法之基于规则的中文分词 目录 常见中文分词方法 推荐中文分词工具 参考链接 一.四种常见的中文分词方法: 基于规则的中文分词 基于统计的中文分词 深度学习中文分词 混合分词方法 ...

  6. C/C++随堂笔记

    注释:行注释 块注释: (1)#if 0 #endif (2)/*     */ <>:表示系统文件 <stdlib.h>+syetem 调用windows中的程序 QT中 c ...

  7. android studio 写一个桌球简单页面

    首先: 保存素材图: 其次: 参考:https://blog.csdn.net/nanhaoluo23/article/details/111144033 一步一步来,导入素材我就卡住了,找不到 于是 ...

  8. [seaborn] seaborn学习笔记8-避免过度绘图Avoid Overplotting

    8 避免过度绘图Avoid Overplotting(代码下载) 过度绘图是散点图及几天常见图表中最常见的问题之一.如下图所示当数据集很大时,散点图的点会重叠,使得图形变得不可读.在这篇文章中,提出了 ...

  9. [OpenCV实战]17 基于卷积神经网络的OpenCV图像着色

    目录 1 彩色图像着色 1.1 定义着色问题 1.2 CNN彩色化结构 1.3 从 中恢复彩色图像 1.4 具有颜色再平衡的多项式损失函数 1.5 着色结果 2 OpenCV中实现着色 2.1 模型下 ...

  10. react 高效高质量搭建后台系统 系列 —— antd和样式

    其他章节请看: react 高效高质量搭建后台系统 系列 antd 后续要做登录模块(主页),不仅要解决请求数据的问题,还需要完成 antd 配置以及样式的准备. antd 多种主题风格 详情请看 这 ...