(转载)Qt之美(二)元对象

本文深入探讨了Qt框架中的Q_OBJECT宏及元对象系统的工作原理,包括如何利用元对象实现信号与槽机制、类型安全的转换等特性。通过具体代码示例展示了moc工具如何帮助开发者更高效地操作类信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

除了D指针,Qt中另一个很有意思的部分就是Q_OBJECT宏了。该宏提供了对元对象的访问,使得能够使用比如信号和槽等QObject的更多特性。元对象提供了诸如类名、属性和方法等的信息,也被称为“反射”。


通过使用QMetaObject,我们能够用如下代码显示一些类的信息:

  1. QObject obj;
  2. const QMetaObject *metaObj = obj.metaObject();
  3. qDebug() << "class name: " << metaObj->className();
  4. qDebug() << "class info count: " << metaObj->classInfoCount();
  5. qDebug() << "methods: ";
  6. // 从QMetaObject::methodOffset()开始打印,使其不会显示父类的方法
  7. for (int i = metaObj->methodOffset(); i < metaObj->methodCount(); ++i)
  8. qDebug() << metaObj->method(i).methodType() << " " << metaObj->method(i).signature();

由于C++并没有提供对这些信息的任何支持,Qt引入了元对象编译器(moc)来完成相应的工作。moc会读取每个头文件,如果发现其中定义的类是继承自QObject,且定义了Q_OBJECT宏,便会创建一个相应的C++源代码文件(moc_*.cpp),来完成这些工作。通过代码生成的工作,Qt不仅能够获得诸如Java等语言的灵活性,还能很好的保证继承自C++的性能和可扩展性

假设我们有如下所示的简单类:

  1. class MyObject : public QObject
  2. {
  3. Q_OBJECT
  4. public:
  5. explicit MyObject(QObject *parent = 0);
  6. void myFunc();
  7. public slots:
  8. void mySlot(int myParam);
  9. signals:
  10. void mySignal(int myParam);
  11. };

moc会自动创建以下信息:

  1. // 保存在QMetaObject::d.data指向的空间,其起始部分是一个QMetaObjectPrivate结构体
  2. static const uint qt_meta_data_MyObject[] = {
  3. 5, // 版本号,其内部结构在Qt开发中有所改变
  4. 0, // 类名,其值为字符串qt_meta_stringdata_MyObject的偏移量
  5. // 以下值为(数量,索引)对
  6. 0, 0, // 类信息
  7. 2, 14, // 这里定义了两个方法,其起始索引为14(即signal部分)
  8. 0, 0, // 属性
  9. 0, 0, // 枚举
  10. 0, 0, // 构造函数
  11. 0, // 标识
  12. 1, // signal数量
  13. // 对于signal、slot和property,其signature和parameters为字符串qt_meta_stringdata_MyObject的偏移量
  14. // signals: signature, parameters, type, tag, flags
  15. 18, 10, 9, 9, 0x05,
  16. // slots: signature, parameters, type, tag, flags
  17. 32, 10, 9, 9, 0x0a,
  18. 0 // eod
  19. };
  20. // 保存在QMetaObject::d.stringdata指向的空间
  21. static const char qt_meta_stringdata_MyObject[] = {
  22. "MyObject/0/0myParam/0mySignal(int)/0"
  23. "mySlot(int)/0"
  24. };

以上信息,及其基类的相关信息,都保存在该类对应的元对象中:

  1. const QMetaObject MyObject::staticMetaObject = {
  2. { &QObject::staticMetaObject, // 指向其基类的元对象,保存在QMetaObject::d.superdata
  3. qt_meta_stringdata_MyObject, qt_meta_data_MyObject, 0 }
  4. };

这样,如果我们希望对QObject的对象进行类型转换,就不需使用开销较大的运算符dynamic_cast, 而能够直接使用qobject_cast。该模板函数利用了元对象系统的信息,避免了在运行时进行类型转换:

  1. template <class T> inline T qobject_cast(QObject *object)
  2. {
  3. #if !defined(QT_NO_QOBJECT_CHECK)
  4. reinterpret_cast(0)->qt_check_for_QOBJECT_macro(*reinterpret_cast(object));
  5. #endif
  6. return static_cast(reinterpret_cast(0)->staticMetaObject.cast(object));
  7. }

这里,目标类型的元对象仅仅检查其是否从自身继承而来:

  1. const QObject *QMetaObject::cast(const QObject *obj) const
  2. {
  3. if (obj) {
  4. const QMetaObject *m = obj->metaObject();
  5. do {
  6. if (m == this)
  7. return obj;
  8. } while ((m = m->d.superdata));
  9. }
  10. return 0;
  11. }

此外,moc会为每一个信号创建相应函数。当信号被emit时,该函数会被自动调用:

  1. void MyObject::mySignal(int _t1)
  2. {
  3. void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
  4. // 检查链接到该信号的所有slot,并根据链接类型进行调用
  5. QMetaObject::activate(this, &staticMetaObject, 0, _a);
  6. }

最后,这些信号都会通过moc创建的qt_metacall函数被调用:

  1. int MyObject::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
  2. {
  3. // 如果该函数已被基类调用,则直接返回
  4. _id = QObject::qt_metacall(_c, _id, _a);
  5. if (_id < 0)
  6. return _id;
  7. // 根据函数的ID进行调用
  8. if (_c == QMetaObject::InvokeMetaMethod) {
  9. switch (_id) {
  10. case 0: mySignal((*reinterpret_cast< int(*)>(_a[1]))); break;
  11. case 1: mySlot((*reinterpret_cast< int(*)>(_a[1]))); break;
  12. default: ;
  13. }
  14. // 删除被该类“消耗”的ID,使得其子类类在处理时ID总是从0开始,而返回值-1则表示该函数已被调用
  15. _id -= 2;
  16. }
  17. return _id;
  18. }
内容概要:本文深入探讨了金属氢化物(MH)储氢系统在燃料电池汽车中的应用,通过建立吸收/释放氢气的动态模型和热交换模型,结合实验测试分析了不同反应条件下的性能表现。研究表明,低温环境有利于氢气吸收,高温则促进氢气释放;提高氢气流速和降低储氢材料体积分数能提升系统效率。论文还详细介绍了换热系统结构、动态性能数学模型、吸放氢特性仿真分析、热交换系统优化设计、系统控制策略优化以及工程验证与误差分析。此外,通过三维动态建模、换热结构对比分析、系统级性能优化等手段,进一步验证了金属氢化物储氢系统的关键性能特征,并提出了具体的优化设计方案。 适用人群:从事氢能技术研发的科研人员、工程师及相关领域的研究生。 使用场景及目标:①为储氢罐热管理设计提供理论依据;②推动车载储氢技术的发展;③为金属氢化物储氢系统的工程应用提供量化依据;④优化储氢系统的操作参数和结构设计。 其他说明:该研究不仅通过建模仿真全面验证了论文实验结论,还提出了具体的操作参数优化建议,如吸氢阶段维持25-30°C,氢气流速0.012g/s;放氢阶段快速升温至70-75°C,水速18-20g/min。同时,文章还强调了安全考虑,如最高工作压力限制在5bar以下,温度传感器冗余设计等。未来的研究方向包括多尺度建模、新型换热结构和智能控制等方面。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值