原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://devbean.blog.51cto.com/448512/355100

前面我们说过,Qt 不是使用的“标准的” C++ 语言,而是对其进行了一定程度的“扩展”。这里我们从Qt新增加的关键字就可以看出来:signals、slots 或者 emit。所以有人会觉得 Qt 的程序编译速度慢,这主要是因为在 Qt 将源代码交给标准 C++ 编译器,如 gcc 之前,需要事先将这些扩展的语法去除掉。完成这一操作的就是 moc。

moc 全称是 Meta-Object Compiler,也就是“元对象编译器”。Qt 程序在交由标准编译器编译之前,先要使用 moc 分析 C++ 源文件。如果它发现在一个头文件中包含了宏 Q_OBJECT,则会生成另外一个 C++ 源文件。这个源文件中包含了 Q_OBJECT 宏的实现代码。这个新的文件名字将会是原文件名前面加上 moc_ 构成。这个新的文件同样将进入编译系统,最终被链接到二进制代码中去。因此我们可以知道,这个新的文件不是“替换”掉旧的文件,而是与原文件一起参与编译。另外,我们还可以看出一点,moc 的执行是在预处理器之前。因为预处理器执行之后,Q_OBJECT 宏就不存在了。

既然每个源文件都需要 moc 去处理,那么我们在什么时候调用了它呢?实际上,如果你使用 qmake 的话,这一步调用会在生成的 makefile 中展现出来。从本质上来说,qmake 不过是一个 makefile 生成器,因此,最终执行还是通过 make 完成的。

为了查看 moc 生成的文件,我们使用一个很简单的 cpp 来测试:

test.cpp

  1. class Test : public QObject
  2. {
  3. Q_OBJECT
  4. public:
  5. explicit Test(QObject *parent = 0);
  6. signals:
  7. public slots:
  8. };

这是一个空白的类,什么都没有实现。在经过编译之后,我们会在输出文件夹中找到 moc_test.cpp:

moc_test.cpp

  1. /****************************************************************************
  2. ** Meta object code from reading C++ file 'test.h'
  3. **
  4. ** Created: Thu Jul 22 13:06:45 2010
  5. **      by: The Qt Meta Object Compiler version 62 (Qt 4.6.3)
  6. **
  7. ** WARNING! All changes made in this file will be lost!
  8. *****************************************************************************/
  9. #include "../test.h"
  10. #if !defined(Q_MOC_OUTPUT_REVISION)
  11. #error "The header file 'test.h' doesn't include <QObject>."
  12. #elif Q_MOC_OUTPUT_REVISION != 62
  13. #error "This file was generated using the moc from 4.6.3. It"
  14. #error "cannot be used with the include files from this version of Qt."
  15. #error "(The moc has changed too much.)"
  16. #endif
  17. QT_BEGIN_MOC_NAMESPACE
  18. static const uint qt_meta_data_Test[] = {
  19. // content:
  20. 4,       // revision
  21. 0,       // classname
  22. 0,    0, // classinfo
  23. 0,    0, // methods
  24. 0,    0, // properties
  25. 0,    0, // enums/sets
  26. 0,    0, // constructors
  27. 0,       // flags
  28. 0,       // signalCount
  29. 0        // eod
  30. };
  31. static const char qt_meta_stringdata_Test[] = {
  32. "Test\0"
  33. };
  34. const QMetaObject Test::staticMetaObject = {
  35. { &QObject::staticMetaObject, qt_meta_stringdata_Test,
  36. qt_meta_data_Test, 0 }
  37. };
  38. #ifdef Q_NO_DATA_RELOCATION
  39. const QMetaObject &Test::getStaticMetaObject() { return staticMetaObject; }
  40. #endif //Q_NO_DATA_RELOCATION
  41. const QMetaObject *Test::metaObject() const
  42. {
  43. return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;
  44. }
  45. void *Test::qt_metacast(const char *_clname)
  46. {
  47. if (!_clname) return 0;
  48. if (!strcmp(_clname, qt_meta_stringdata_Test))
  49. return static_cast<void*>(const_cast< Test*>(this));
  50. return QObject::qt_metacast(_clname);
  51. }
  52. int Test::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
  53. {
  54. _id = QObject::qt_metacall(_c, _id, _a);
  55. if (_id < 0)
  56. return _id;
  57. return _id;
  58. }
  59. QT_END_MOC_NAMESPACE

可以看到,moc_test.cpp 里面为 Test 类增加了很多函数。然而,我们并没有实际写出这些函数,它是怎么加入类的呢?别忘了,我们还有 Q_OBJECT 这个宏呢!在 qobjectdefs.h 里面,找到 Q_OBJECT 宏的定义:

  1. #define Q_OBJECT \
  2. public: \
  3. Q_OBJECT_CHECK \
  4. static const QMetaObject staticMetaObject; \
  5. Q_OBJECT_GETSTATICMETAOBJECT \
  6. virtual const QMetaObject *metaObject() const; \
  7. virtual void *qt_metacast(const char *); \
  8. QT_TR_FUNCTIONS \
  9. virtual int qt_metacall(QMetaObject::Call, int, void **); \
  10. private:

这下了解了:正是对 Q_OBJECT 宏的展开,使我们的 Test 类拥有了这些多出来的属性和函数。注意,QT_TR_FUNCTIONS 这个宏也是在这里定义的。也就是说,如果你要使用 tr() 国际化,就必须使用 Q_OBJECT 宏,否则是没有 tr() 函数的。这期间最重要的就是 virtual const QMetaObject *metaObject() const; 函数。这个函数返回 QMetaObject 元对象类的实例,通过它,你就获得了 Qt 类的反射的能力:获取本对象的类型之类,而这一切,都不需要 C++ 编译器的 RTTI 支持。Qt 也提供了一个类似 C++ 的 dynamic_cast() 的函数 qobject_case(),而这一函数的实现也不需要 RTTI。另外,一个没有定义 Q_OBJECT 宏的类与它最接近的父类是同一类型的。也就是说,如果 A 继承了 QObject 并且定义了 Q_OBJECT,B 继承了 A 但没有定义 Q_OBJECT,C 继承了 B,则 C 的 QMetaObject::className() 函数将返回 A,而不是本身的名字。因此,为了避免这一问题,所有继承了 QObject 的类都应该定义 Q_OBJECT 宏,不管你是不是使用信号槽。

本文出自 “豆子空间” 博客,请务必保留此出处http://devbean.blog.51cto.com/448512/355100

qmake和moc的功能(★firecat推荐★)的更多相关文章

  1. Chrome/Chromium的实验性功能+扩展推荐,让你的Chrome/Chromium起飞!

    1 实验性功能 Chrome/Chromium内置了一些很酷的实验性功能,打开 chrome://flags 即可访问.打开这些实验性功能后,浏览器的使用体验会更好,这里Chrome的版本为80.0. ...

  2. 关于栈和堆的定量分析(★firecat推荐★)

    文章来源:http://blog.csdn.net/bigbug_zju/article/details/39525281 计算机系统中的堆和栈是跟程序员最密切的两个概念.如果没有栈和堆的概念,下面程 ...

  3. 收藏的博客 -- Qt/C++学习

    Qt Creator环境: 使用Qt Creator作为Linux IDE,代替Vim:实现两台Linux电脑远程部署和调试(一台电脑有桌面系统,一台电脑无桌面系统) 使用Qt Creator作为Li ...

  4. 翻译qmake文档(一) qmake指南和概述

    翻译qmake文档 目录 英文文档连接: http://qt-project.org/doc/qt-5/qmake-manual.html http://qt-project.org/doc/qt-5 ...

  5. qmake, makefile, make是什么东东,makefile简介!

    qmake是一个协助简化跨平台开发的构建过程 的工具,Qt附带的工具之一 .qmake能够自动生成Makefile.Microsoft Visual Studio 专案文件 和 xcode 专案文件. ...

  6. 翻译qmake文档(三) Creating Project Files

    翻译qmake文档 目录   原英文文档:http://qt-project.org/doc/qt-5/qmake-project-files.html   创建项目文件 项目文件包含qmake构建你 ...

  7. 我为什么推荐你使用kindle

    我为什么推荐你使用kindle kindle 分 kindle 电子阅读器,pc 版,app 版,下文主要介绍 Amazon 设计和销售的电子书阅读器. 亚马逊官方出的 kindle 使用技巧 使用 ...

  8. 使用Vue-Router 2实现路由功能

    转自:http://blog.csdn.net/sinat_17775997/article/details/54710420 注意:vue-router 2只适用于Vue2.x版本,下面我们是基于v ...

  9. 开源项目推荐:e-example / Springboot+bootstrap + ……

    前言: 我想要找一个 springboot + bootstrap 的例子介绍,然后搜索到了这个开源项目. 所有能跑起来的项目都有研究价值,看看这个项目的文档.目前正好满足我想要的功能.推荐 正文: ...

随机推荐

  1. eclipse tomcat 网页404的一个小问题

    之前一篇文章说过关于修改tomcat布置的应用的localhost路径.因为有两个项目在eclipse,所以我每次启动tomcat的时候都会加载两个项目, 但我其实只用调试其中一个项目,所以我就在se ...

  2. 修改http中的refer(转)

    Referrer的重要性 HTTP请求中有一个referer的报文头,用来指明当前流量的来源参考页.例如在www.sina.com.cn/sports/上点击一个链接到达cctv.com首页,那么就r ...

  3. JS-Math内置对象

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  4. [React Testing] Children with Shallow Rendering

    When testing React components, we often want to make sure the rendered output of the component match ...

  5. codeforce 437B The Child and Set

    time limit per test 1 second memory limit per test 256 megabytes input standard input output standar ...

  6. 论js闭包的重要性

    很久没写博客了,今天发现了一个很有意思的问题,写下来分享一下 话不多说,贴前端代码: <script type="text/javascript" src="js/ ...

  7. 封装curl类,post get方法实现网站请求

    <?phpclass RamDemo{    //get方法    function RamGet($url,$arr)    {        if($arr!=''){           ...

  8. 小学生之手(01)之 "for循环"

    ---恢复内容开始--- 咳咳咳!第一次要写这种东西,要是有不足的地方,请见谅!!!并且感觉在这班门弄斧是不是有点托大了.一向擅长低调的我,在’被逼无奈‘之下,要嚣张一下了......(此处省略500 ...

  9. datagrid数据导出到excel文件给客户端下载的几种方法

    方法一:导出到csv文件,存放在服务器端任一路径,然后给客户下载 优点: 1.可以进行身份认证后给客户下载,如果放到非web目录就没有对应的url,客户无法随时下载. 2.也是因为生成了文件,所以占用 ...

  10. XenServer 使用笔记

    XenServer 模拟千兆网卡 这两天用 XenServer 安装 VM,其中一台 VM 是用作无盘测试的 Linux Server,不在主流发行版之列,无奈 XenServer 日前对非主流的 L ...