Meta-Object系统为我们提供了信号-槽机制、运行期类型信息和动态属性系统。
Meta-Object系统是基于以下三点才能正常运行的:
1. QObject做为一个基类,让派生至它的类能使用到Meta-object系统的各种特性;
2. 在类声明中使用到的宏Q_OBJECT,使得Meta-object系统的各种特性可用;
3. Meta-Object Compiler(moc)为所有QObject派生类提供了Meta-object特性的实现代码;
在编译的时候Moc工具会去读取c++源文件,如果发现类声明中包含了宏Q_OBJECT,它会自动生成另外一份c++源文件,为每一个类添加了Meta-object的实现代码。
除了提供信号-槽机制,Meta-object代码还提供了以下几点特性:
1. QObject::MetaObject()返回这个类所关联的Meta-object;
2. QMetaObject::className()在运行期以字符串的形式返回类的名称,没有使用c++编译器自带的RTTI;
3. QObject::inherits()判断一个对象的类是否派生至另一个类;
4. QObject::tr()和QObject::trUtf8()在国际化中用来翻译字符串
5. QObject::setproperty()和QObject::property()通过名称动态的设置或获取属性;
6. QMetaObject::newInstance()构造一个类的新的实例;
我们还可以使用qobject_cast()来对QObject类进行动态强转。Qobject_cast()方法的作用和标准c++中的dynamic_cast()很相似,但是它没有使用RTTI,并且可以跨dll。
当然,我们也可以在不添加Q_OBJECT宏和没有Meta-object实现代码的情况下使用一个QObject子类,但是这样的话就没有信号-槽等其他特性可以使用。从Meta-object系统的立场上看,一个没有Meta代码的QObject子类等价于派生层次中离它最近的包含Meta代码的父类。也就是说,QMetaObject::className()方法返回的不是这个类的名称,而是它的包含Meta代码的父类名称。
因此,我们强烈建议所有QObject子类都应该使用Q_OBJECT宏,不论你是不是要用信号-槽和属性。