Qt学习 -- Meta_Object Model系统

转载 2018年04月16日 15:45:41

Meta_Object Model系统

Qt meta-object系统基于三个方面:

  1. QObject提供一个基类, 方便派生类使用meta-object系统的功能;
  2. Q_OBJECT宏,在类的声明体内激活meta-object功能,比如动态属性、信号、槽;
  3. Meta Object编译器(MOC),为每个QObject派生类生成代码,已支持meta-object功能。

QObject定义了从一个QObject对象访问meta-object功能的接口Q_OBJECT宏用来告诉编译器该类需要激活meta-object功能编译器在扫描一个源文件时如果发现类的声明中有这个宏就会生成一些代码来为支持meta-object功能——主要是生成该类对应 MetaObject类以及对QObject的函数override。

QObject和QMetaObject:
顾名思义QMetaObject包含了QObject的所谓的元数,也就是QObject信息的一些描述信息除了类型信息还包含QT中特有的signal&slot信息。

QObject::metaObject()方法返回一个QObject对象对应的metaobject对象,注意这个方法是virtual方法。如上文所说,如果一个类的声明中包含了Q_OBJECT宏,编译器会生成代码来实现这个类对应的QMetaObject类,并重载QObject::metaObject()方法来返回这个QMetaObject类的实例引用。这样当通过QObject类型的引用调用metaObejct方法时,返回的是这个引用的所指的真实对象的 metaobject。

如果一个类从QObject派生,确没有声明Q_OBJECT宏,那么这个类的metaobject对象不会被生成,这样这个类所声明的signal&slot都不能使用,而这个类实例调用metaObject()返回的就是其父类的metaobject对象,这样导致的后果就是你从这个类实例获得的元数据其实都是父类的数据,这显然给你的代码埋下隐患。因此如果一个类从QObject派生,它都应该声明Q_OBJECT宏,不管这个类有没有定义 signal&slot和Property。

除了为对象间的通信提供信号与槽(引入元对象系统的主要原因)机制外,元对象还提供以下特性:

  • QObject::metaObject()返回类关联的meta-object对象。
  • QMetaObject::className()在运行时以字符串的形式返回类名,无需C++编译器提供运行时类别信息(RTTI)的支持。
  • QObject::inherits()返回一个对象是否是QObject继承树上一个类的实例。
  • QObject::tr()和QObject::trUtf8()提供国际化支持,将字符串翻译成指定的语言。
  • QObject::setProperty()和QObject::property()通过名称动态设置和获取属性。
  • QMetaObject::newInstance()构造类的一个新实例。

类型转换

除此之外,还可以用qobject_cast()动态转换QObject类的类型。qobject_cast()函数和标准C++的dynamic_cast()功能类似,它的优点在于:不需要RTTI的支持,而且可以跨越动态连接库的转换。它尝试将它的参数转换成尖括号内的指针类型,如果对象是正确的类型(在运行时检查),则返回非零指针;否则,返回0,说明对象类型不兼容。

例如,假设MyWidget继承自QWidget,同时也声明了Q_OBJECT宏。

QObject *obj = new MyWidget;

QObject *类型的变量obj实际上指向一个MyWidget对象,因此,我们可以适当地进行类型转换:

QWidget *widget = qobject_cast<QWidget *>(obj);

因为obj实际上是一个MyWidget,而MyWidget是QWidget的子类,所以,从QObject转换为QWidget成功了。既然知道了obj是MyWidget类型的,那么我们也可以将其转换为MyWidget *:

MyWidget *myWidget = qobject_cast<MyWidget *>(obj);

到MyWidget类型的转换也是成功的,因为qobject_cast()并不区分内建的Qt类型和自定义类型。可是,转换到QLabel却失败了,返回的指针为0。

QLabel *label = qobject_cast<QLabel *>(obj);// label0

QMetaObject

每个QObject类都有一个对应的QMetaObject类,形成一个平行的类型层次。

QMetaObject提供的信息:
下面通过QMetaObject的接口来解读QMetaObject提供的信息:

1、基本信息

const char * className () constconst QMetaObject * superClass () const

2、classinfo: 提供额外的类信息。其实就是一些名值对。 用户可以在类的声明中以Q_CLASSINFO(name, value)方式添加。

int classInfoCount () const
int classInfoOffset () const
QMetaClassInfo classInfo ( int index ) const
int indexOfClassInfo ( const char * name ) const

3、contructor:提供该类的构造方法信息

QMetaMethod constructor ( int index ) const
int constructorCount () const
int indexOfConstructor ( const char * constructor ) const

4、enum:描述该类声明体中所包含的枚举类型信息

QMetaEnum enumerator ( int index ) const
int enumeratorCount () const
int enumeratorOffset () const
int indexOfEnumerator ( const char * name ) const

5、method:描述类中所包含方法信息:包括property,signal,slot等,包括祖先类,如何组织暂时不确定。

QMetaMethod method ( int index ) const
int methodCount () const
int methodOffset () const

int indexOfMethod ( const char * method ) const
int indexOfSignal ( const char * signal ) const
int indexOfSlot ( const char * slot ) const

6、property:类型的属性信息

QMetaProperty property ( int index ) const
int propertyCount () const
int propertyOffset () const
int indexOfProperty ( const char * name ) const
QMetaProperty userProperty () const  //返回类中设置了USER flag的属性

注意:对于类里面定义的函数,构造函数,枚举,只有加上一些宏才表示你希望为方法提供meta信息。比如 Q_ENUMS用来注册宏,Q_INVACABLE用来注册方法(包括构造函数)。Qt这么设计的原因应该是避免meta信息的臃肿。

moc文件分析

我们知道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 宏就不存在了。

总结

至此,我们应该是对Qt Meta-Object Model有了一个清楚的认识

  • Qt提供了一个QObject的基类
  • Qt扩展了C++语法,提供了Q_OBJECT、Q_INVOKABLE、signals、slots、emit、SIGNAL,SLOT、Q_PROPERT、Q_ENUM、Q_FLAG、Q_CLASSINFO等宏,moc会识别这些宏并生成对应的moc源代码
  • Q_OBJECT宏中声明了QMetaObject的静态对象,QMetaObject中记录了classinfo、method、property、enum,并提供了metacall来操作

基于QT的空气监测系统

本实践项目是嵌入式开发、物联网,创客综合实践项目。 项目开发使用的技术知识点包括:C++语言编程,Qt程序设计,Qt移植开发板,python编程,文件编程,串口编程,驱动程序开发。
  • 2017年05月04日 13:36

深刻理解 Meta-Object系统与moc的作用

我们知道Qt 不是使用的“标准的” C++ 语言,而是对其进行了一定程度的“扩展”。这里我们从Qt新增加的关键字就可以看出来:signals、slots 或者 emit。所以有人会觉得 Qt 的程序...
  • Andy_93
  • Andy_93
  • 2016-10-09 09:27:16
  • 883

Qt之Meta-Object系统

简述Qt的元对象系统(Meta-Object System)提供了信号与槽机制,可用于对象间通信、运行时类别信息和动态属性系统。元对象系统基于三个方面: QObject类:为Objects提供了一个可...
  • u011012932
  • u011012932
  • 2016-07-25 10:44:51
  • 5502

【Qt入门实践】Meta-Object的重要性和使用原理

Meta-Object系统为我们提供了信号-槽机制、运行期类型信息和动态属性系统。   Meta-Object系统是基于以下三点才能正常运行的: 1.      QObject做为一个基类,让派生至它...
  • feng1790291543
  • feng1790291543
  • 2015-03-13 21:23:40
  • 781

Qt 系统学习目录

Qt 简介     Qt 是一个著名的 C++ 应用程序框架。你并不能说它只是一个 GUI 库,因为 Qt 十分庞大,并不仅仅是 GUI 组件。使用 Qt,在一定程度上你获得的是一个“一站式”的...
  • imxiangzi
  • imxiangzi
  • 2015-09-02 11:17:26
  • 949

Qt学习之路(45): 自定义model之一

Qt学习之路(45): 自定义model之一 2010-01-17 23:50:05 标签:C++ 教程 学习 QT教程 Qt 原创作品,允许转载,转载时请务必以超链接形式标明文...
  • carrie0728
  • carrie0728
  • 2016-07-12 17:26:15
  • 669

【QT学习】View和Model

http://doc.trolltech.com/main-snapshot/model-view-programming.html 介绍 Qt 4推出了一组新的item view类,它们使用mo...
  • Jammg
  • Jammg
  • 2016-06-20 02:32:58
  • 2057

Qt Model/View/Delegate 机制学习

Qt Model/View 学习笔记 (一) 介绍 Qt 4推出了一组新的item view类,它们使用model/view结构来管理数据与表示层的关系。这种结构带来的 功能上的分离...
  • laryyzhao
  • laryyzhao
  • 2012-06-07 08:47:50
  • 2958

QT View及Model源码解析

QT的Model用于保存数据,而QTView只是用于显示界面,大概关系如下,View的数据private中一般会有drawcell等方法,用于从model里面取数据绘制文字,表格,绘制的时候会根据每个...
  • hjing1988
  • hjing1988
  • 2015-01-01 10:43:56
  • 3413

Qt表格之Model/View实现

Qt Model/View
  • soso101
  • soso101
  • 2014-10-28 21:12:53
  • 3134
收藏助手
不良信息举报
您举报文章:Qt学习 -- Meta_Object Model系统
举报原因:
原因补充:

(最多只允许输入30个字)