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函数的调用,导致所有连接上的槽函数被调用
最新文章
- Windows Phone 六、JSON序列化
- CF449C Jzzhu and Apples (筛素数 数论?
- 解决tkinter在windows上没有正确安装的问题
- Codeforces Round #192 (Div. 2) A. Cakeminator
- spring注入简记
- HNOI2017 滚粗记
- Java IO学习笔记(一)
- git合并代码解决冲突
- Kickstart 和 Cobbler ks.cfg文件详解
- log4j2.xml日志文件设置文件路径
- Python快速学习10: 循环的对象及设计 (生活的规律)
- 2018-01-19 Xtext试用: 5步实现一个(中文)JVM语言
- MVC 使用cshtml的一些基础知识-和相关整理
- C# CEF 封装UserControl
- OnSen UI结合AngularJs打造”美团";APP";订单”页面 --Hybrid App
- CenterOS下安装Nginx
- C Mysql API连接Mysql
- ThinkPHP getBy动态查询
- video.js视频播放器
- 构建配置 ProGuard Shrink 混淆和压缩
热门文章
- nuxt作为主应用接入qiankun的实践(附代码)
- 整理 js 日期对象的详细功能,使用 js 日期对象获取具体日期、昨天、今天、明天、每月天数、时间戳等,以及常用的日期时间处理方法
- 【Phoenix】简介、架构、存储、入门、常用表操作、表的映射方式、配置二级索引
- golang在win10安装、环境配置 和 goland(IDE开发golang配置)
- MongoDB从入门到实战之Docker快速安装MongoDB
- 已完成 10000 多次提交,Solon Java Framework v1.12.1 发布
- JavaScript 图像压缩
- Java学习笔记:2022年1月7日
- 【实战】yolov8 tensorrt模型加速部署
- 分布式协议与算法-Raft算法