解析Qt元对象系统(一) 概述

Meta-Object System 提供了Qt的信号和槽机制以及对象之间的互相通信,运行时的信息和动态属性系统。

三个必要条件:
1. QObject的子类
2. 宏Q_OBJECT
3. Meta Object Compiler

Qt官方建议对自定义的QObject子类都要加这个宏,但要注意:某些类不是继承自QObject,这些类里加Q_OBJECT就会出错,例如QEvent,QGraphicsItem,QRunnable.

MOC的实现是一个预处理器,使用MOC的方式,所有平台上的标准的C++编译器都能支持Qt。从而不需要实现一个新的跨平台的Qt编译器。moc是为了解决反射的问题,但是一些动态的编程语言(如Python,Ruby等)中,语言本身自带反射功能。Qt程序之所以编译速度慢,主要是因为在 Qt 将源代码交给标准C++编译器,如gcc之前,需要事先将这些扩展的语法去除掉。完成这一操作的就是 moc。

如果工程是用qmake生成Makefile进行编译,那么其中就包含了调用moc的规则,我们不必直接使用moc.exe。moc.exe会读取头文件,查看是否有Q_OBJECT宏定义,如果有则根据这个头文件生成相应的moc_.cpp,该文件同样将进入编译系统,最终被链接到二进制代码中去,QtCreator生成的代码就是通过编译链接时,把moc_widget.o与其他目标文件链接到一起,这种方式不用改源代码,相对而言比较顺眼。

moc_.cpp主要实现了头文件中的Q_OBJECT宏和SIGNAL,也就是将Qt扩展的语法去掉,再交给C++编译器。
SIGNAL只在头文件做声明,但我们写Qt程序时从不进行实现,因为它是在moc_.cpp里实现的,
例如无参数信号void Text();的实现:

void MainWindow::Text()
{
    QMetaObject::activate(this, &staticMetaObject, 0, nullptr);
}

有参数信号void time(QDateTime t);的实现:

void MainWindow::time(QDateTime _t1)
{
    void *_a[] = { nullptr, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
    QMetaObject::activate(this, &staticMetaObject, 1, _a);
}

主要调用QMetaObject::activate方法,staticMetaObject是这个类默认的一个静态元对象。第三个参数是信号对应的序数。第四个参数如果是nullptr则代表信号无参数,否则代表参数的指针。

moc文件也可以在cpp文件中被include,Qt官方示例很多就是这样做的,我们也可以这样写常见的MainWindow程序:

#include 
#include 

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent=0):
        QMainWindow(parent)
    {}
    ~MainWindow()
    {}
};

#include "main.moc"
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow m;
    m.resize(800,600);
    m.show();
    return a.exec();
}

编译之前先运行qmake,以处理宏Q_OBJECT,生成main.moc。如果没有#include "main.moc",会报错:
无法解析3个外部符号,即moc文件中实现的3个函数:qt_metacall, qt_metacast, metaObject

元对象系统涉及到的类: QMetaType, QMetaMethod, QMetaObject, QMataClassInfo, QMetaEnum, QMetaDataReaderControl, QMetaProperty,

QMataType是Qt所支持的元类型,有个Type的枚举,这个枚举列表中的所有类型是Qt信号槽机制本身就支持的,大部分的类型实际在宏QT_FOR_EACH_STATIC_TYPE中包含。如果是自定义的类型需要用qRegisterMetaType去注册元类型才能被Qt的信号槽所识别。

QMetaMethod有个重要的成员函数invoke,支持跨线程调用,是基于元对象系统的。

QMetaObject是元对象类本身,实现了QMetaObject::invokeMethod, 功能和QMetaMethod没有什么区别。提供了元对象系统的基本方法,包括方法/信号槽/属性的数目/序数等等方法。

QMataClassInfo提供了类的附加信息。

元对象系统的一些常用工具:

  • QObject::metaObject(),返回当前类的元对象信息,是个QMetaObject指针;QObject::staticMetaObject也可以获取当前类的元对象信息,类型是QMetaObject。
  • QMetaObject::className(),运行时返回类名,返回类型是char*。
  • QMetaObject::newInstance(),构造一个新的实例。
  • QObject::inherits(),判断当前对象实例的类继承关系,常用于判断某个对象属于哪个类。
  • QObject::tr() 和QObject::trUtf8()用于Qt语言国际化,返回类型是QString。
  • QObject::property()/setProperty(),通过属性名动态获取/修改属性值。
  • qobject_cast(),动态类型转换,类似于标准C++的dynamic_cast(),不同的是它不需要RTTI(run time type information)且不受动态库的限制。

你可能感兴趣的:(Qt)