• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
invisible_man
博客园    首页    新随笔    联系   管理    订阅  订阅

Qt元对象系统简介

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

Q_OBJECT 宏声明了在每一个QObject子类中必须首选的内省函数:metaObject(),tr(),qt_metacall()以及其他一些函数

Qt的moc工具生成了用于Q_OBJECT声明的所有函数和所有信号的实现

同时也提供了connect()和disconnect()这样的内省函数

 

 

Qt 不使用标准的C++语言,而是进行了一定程度的扩展,增加了一些新的关键字(例如 signals、slots、emit 等),并实现了反射(内省)机制。

我们知道,C++的对象内存模型非常干净,只有成员变量和成员函数,没有保留额外的类型信息,这使得C++非常高效。所谓类型信息,就是对象所属的类、所包含的成员函数和成员变量(以及它们的修饰符)、所在的继承关系等。类型信息用来描述一个对象的各种属性。

虽然C++提供了RTTI机制,但非常简陋,对象被创建后仅能获得类的名字,这使得RTTI不堪重用,如同鸡肋。像Java、C#等面向对象的语言,可以通过对象完整还原出类的信息,例如类的名字、父类、类所包含的成员变量和成员函数以及它们的修饰符等。这被称作反射机制或内省机制,也就是说对象可以认知自己。

反射机制无疑会增加额外的存储空间,在效率上有所牺牲,而且在普通程序中没有用武之地,为了保持几乎与C同等的效率,C++不提供反射机制也有一定的道理。

但对于大型框架或类库来说,反射机制有时很有必要,它会增加程序的灵活性和动态性,例如动态加载类、解耦等。最明显的一个例子是编译器的智能提示,当输入完对象的名称,再输入.或->,就会提示该对象拥有的变量和函数,这是反射机制的典型应用。

如今,C++的反射机制在 Qt、Boost 等框架中的实现已经非常成熟。

moc

Qt 在将源代码交给标准C++编译器之前,例如GCC、VS等,需要提前将这些扩展的语法去除掉。完成这一操作的就是 moc。

moc 全称是"Meta-Object Compiler",也就是”元对象编译器“。moc 就是一个源代码分析程序,它会读取C++源文件,如果发现在一个头文件中包含了宏 Q_OBJECT,则会生成另外一个C++源文件。这个源文件中包含了 Q_OBJECT 宏的实现代码。这个新文件的名字将由源文件名加上moc_前缀构成,读者可以在 Debug 或 Release 目录中找到。

新文件并不会替换旧文件,而是与旧文件一起进入编译系统,最终被链接到二进制代码中去。

可以发现,moc 的执行在C++预处理器之前,因为预处理器执行之后会进行宏替换,Q_OBJECT 就不存在了。

 

元对象系统

Qt中的元对象系统是用来处理对象间通讯的信号/槽机制、运行时的类型信息和 动态属性系统。

它基于下列三类:

  1. QObject类;为所有需要利用原对象系统的对象提供了一个基类。
  2. 类声明中的私有段中的Q_OBJECT宏;通常可以声明在类的私有段中,让该类可以使用元对象的特性,比如动态属性,信号和槽。
  3. 元对象编译器(moc)。元对象编译器(moc)为每个QObject子对象自动生成必要的代码来实现元对象特性。

moc读取C++源文件。如果它发现其中包 含一个或多个类的声明中含有Q_OBJECT宏,它就会给含有Q_OBJECT宏的类生成另一个 含有元对象代码的C++源文件。这个生成的源文件可以被类的源文件包含(#include) 到或者和这个类的实现一起编译和连接。

除了提供对象间通讯的信号和槽机制之 外(介绍这个系统的主要原因),QObject中的元对象代码还提供以下特征:

  • className()函数在运行的时候以 字符串返回类的名称,不需要C++编译器中的本地运行类型信息(RTTI)的支持。
  • inherits()函数返回这个对象是否 是一个继承于QObject继承树中一个特定类的类的实例。
  • tr()和trUtf8() 两个函数是用于国际化中的字符串翻译。
  • setProperty()和property()两个函数是用来通过名称动态设置和 获得对象属性的。
  • metaObject()函数返回这个类 所关联的元对象。

虽然你使用QObject作为一个基类而不使用Q_OBJECT宏和元对象代码是可以的, 但是如果Q_OBJECT宏没有被使用,那么这里的信号和槽以及其它特征描述都不会被 提供。根据元对象系统的观点,一个没有元代码的QObject的子类和它含有元对象代 码的最近的祖先相同。举例来说就是,className()将不会返回你的类的实际名称, 返回的是它的这个祖先的名称。我们强烈建议QObject 的所有子类使用Q_OBJECT宏,而不管它们是否实际使用了信号、槽和属性

http://blog.csdn.net/tingsking18/article/details/4800828

 

posted @ 2017-05-21 14:59  invisible_man  阅读(683)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3