Qt Meta-Object System
转自:http://blog.sina.com.cn/s/blog_640531380100sikl.html
Qt的Meta-Object System提供了signals/slots机制中,物件之间能够做联繫、run-time type informaion以及dynamic property system…等功能。
Meta-Object System 的基础如下:
1. QObject 类别为所有物件的基础类别(才能够使用meta-object system)
2. Q_OBJECT macro(巨集),置于类别宣告中的private区域中,如此才能够使用meta-object大部分功能,包括dynamic properties、signals、slots
3. Meta-Object Compiler (moc) 产生QObject子类别所需的程式码,如此才能够执行meta-object的功能
moc 会读取C++原始档,如果它发现一或多个类别宣告有包含Q_OBJECT macro(就是宣告时,有写macro)时,就会产生出另外的C++档,这个档提供了这些类别的meta-object程式码,通常会被include 进类别原始档,或是以较常见的方式被compile与link于类别实做中。
除了提供signals/slots机制之外,meta-object程式码亦提供下列额外的功能:
* QObject::metaObject() 会回传此类别相关的meta-object
* QMetaObject::className() 会在run-time时回传类别名称(字串型态),而不需要C++ compiler所支援的native run-time type information(RTTI)
* QObject::inherits() 当一个物件是继承自某特定类别的子类别(为QObject继承的顺序)的instace时,此函式会return
* QObject::tr() 和 QObject::trUtf8() 会将字串做翻译处理
* QObject::setProperty() 和 QObject::property() 会动态根据名称设定与取得property
在使用QObject类别的 qobject_cast 时,也可能会执行动态的型态转换(dynamic cast)。qobject_cast()函式类似于标准C++的dynamic_cast(),但有不需要RTTI支援的优点,此外也可以运作于夸动态 函式库(dynamic library)的范围。它将会把参数转换为指标型态(会用”<>”符号来标示),如果物件是正确的 型态(在run-time时)回传一个非null的指标;但如果物件型态不相容,则回传null指标。
举例说明,假定MyWidget是继承字QWidget,并且在宣告时有加入Q_OBJECT macro:
QObject *obj = new MyWidget;
则资料型态是QObject * 的变数obj,实际上是指向MyWidget的指标,我们可用下列方式做型态转换:
QWidget *widget = qobject_cast<QWidget *>(obj);
因为物件实为MyWidget(QWidget的子类别),所以这样的型态强制转换并无错误。既然我们知道obj是MyWidget,就可以直接强 制转换到MyWidget *:
MyWidget *myWidget = qobject_cast<MyWidget *>(obj);
因为qobject_cast()会将内建的Qt型态与自行建立的型态(此例中的MyWidget)视为相同,所以这样的型态强制转换并无错误。
QLabel *label = qobject_cast<QLabel *>(obj);
// label is 0
但上面的强制转换却会将指标设为null。
不过Qt中,可以在run-time时,根据型态来处理不同型态物件之间的转换:
if (QLabel *label = qobject_cast<QLabel *>(obj)) {
label->setText(tr(”Ping”));
} else if (QPushButton *button = qobject_cast<QPushButton *>(obj)) {
button->setText(tr(”Pong!”));
}
值得注意的一点,如果没有Q_OBJECT macro,除了不能自行定义signals/slots之外,其他上述的功能亦将无法使用。从meta-object system的观点来看,如果 QObject 的子类别没有meta code的话,QMetaObject::className()将不回传你的类别名称,而是类别的祖先的名称。因此,这边建议即便没有使用 signals/slots机制,或其他相关的功能,在QObject的子类别还是把Q_OBJECT macro引进来使用比较好。
可参考QMetaObject、Qt’s Property System 以及 Signals and Slots
*注意:
由于qmake并不会处理 .cpp中的Q_OBJECT(通常也很少有人会把Q_OBJECT写在.cpp,而是写在.h中),所以,如果.cpp中有Q_OBJECT的话,则会 产生出 undefined reference to ‘vtable for xxx 这种错误,解决方法就是自己用moc来来处理.cpp中的Q_OBJECT(但官方似乎不太建议自己用moc来处理,而是把Q_OBJECT放在.h档 中),但这边还是说明一下要怎麽自己动手用moc。
* 若xxx.cpp中包含有O_OBJECT,可以先用下面的指令来处理当中的Q_OBJECT
moc xxx.cpp -o xxx.moc
* 接着输入qmake -project、qmake,若没事可以看看Makefile中,已经针对xxx.moc有作处理囉,类似如下:
xxx.moc: xxx.cpp
/opt/qtsdk-2009.01/qt/bin/moc $(DEFINES) $(INCPATH) xxx.cpp -o xxx.moc
* 最后只需要把 #include “xxx.moc” 放到 xxx.cpp 最尾端(一定要放最后一行),然后再make就没有问题囉。