>Qt的meta-object system提供了signals-slots的机制; 它可以可以进行对象间通信, 支持运行时类型的信息和动态属性dynamic properties系统;
基于3个方面
1) QObject类 - 为所有能利用meta-object system的对象提供一个基类;
2) Q_OBJECT宏 - 放在类声明的private部分, 可以使类能使用meta-object的特性, 比如动态属性, signals-slots;
3) moc(Meta-Object Compiler)为每个QObject的子对象生成必要的代码, 来实现meta-object特性;
>moc工具会读入C++源文件. 如果找到包含Q_OBJECT宏的类, 它就创建另一个包含meta-object代码的C++源文件; 这个新生成的源文件需要#inlcude到类的源文件内, 或者和类的实现一起编译和链接;
>除了为对象间的通信提供signals-slots机制, meta-object代码还提供以下特性:
-QObject::metaObject() 返回和类绑定的meta-object;
-QMetaObject::className() 在运行时返回string类型的类名, 不需要通过C++编译器原生的运行时类型信息RTTI的支持;
-QObject::inherits() 如果对象是QObject继承树上的一个类的实例, 返回true;
-QObject::tr()和QObject::trUtf8() 提供字符串的国际化翻译功能;
-QObject::setProperty()和QObject::property() 通过对象名字来动态设置和获取属性;
-QMetaObject::newInstance() 构造这个类的新的实例;
>使用qobject_cast()动态转换QObject类的类型; qobject_cast()函数和标准C++的dynamic_cast类似, 优点是不需要RTTI支持, 而且它可以跨越动态库的边界; 它会试着将参数cast成尖括号内的指针类型, 如果对象类型正确(运行时判定), 返回非0指针, 类型不匹配则返回0;
Example
//假设MyWidget继承自QWidget,声明了Q_OBJECT宏 QObject *obj = new MyWidget; //obj变量是类型为QObject的指针,实际指向MyWidget对象,因此可以这样转换: //从QObject到QWidget的转换是成功的,因为object指向MyWidget类型,是QWidget的子类; QWidget *widget = qobject_cast<QWidget *>(obj); //obj指向MyWidget,所以也可以转换成MyWidget; //到MyWiget的转换是成功的, 因为qobject_cast()对Qt内建类型和自定义类型没有区别对待; MyWidget *myWidget = qobject_cast<MyWidget *>(obj); //到QLable的转换失败,指针会被设为0; QLabel *label = qobject_cast<QLabel *>(obj); //这样可以在运行时根据不同类型的对象,进行不同的处理 if (QLabel *label = qobject_cast<QLabel *>(obj)) { label->setText(tr("Ping")); } else if (QPushButton *button = qobject_cast<QPushButton *>(obj)) { button->setText(tr("Pong!")); }
>虽然在使用Object作为基类时可以不加上Q_OBJECT宏和meta-obejct代码, 但是这样的话signals-slots和其他的特性都无法使用; 从meta-object系统的观点来看, 一个没有meta-object代码的QObject子类和它的具备meta-object代码的最近的基类是相同的; 举例来说, QMetaObject::className()不会返回本类确切的名字, 而是返回基类的名字;
>因此, 我们强烈建议所有的QObject子类都使用Q_OBJECT宏, 不论是否使用signals-slots和属性;
End
<Refer to> http://qt-project.org/doc/qt-5.0/qtcore/metaobjects.html