欢迎转载,请注明出处:https://blog.csdn.net/qq_39453936?spm=1010.2135.3001.5343
原文链接: https://blog.csdn.net/qq_39453936/article/details/120535137
元对象系统 Meta-Object System
一、基础组成
Qt 的元对象系统(Meta-Object System)提供了对象之间通信的信号与槽机制、运行时类型信息和动态属性系统。
- 类:QObject,为所有需要利用原对象系统的对象提供了一个基类。
- 宏:Q_OBJECT,通常可以声明在类的私有段中,让该类可以使用元对象对象的特性,比如动态属性,信号和槽。
- 编译器:元对象编译器(moc)为每个QObject子对象自动生成必要的代码来实现元对象特性。
构建项目时,MOC 工具读取 C++ 源文件,当它发现类的定义里有 Q_OBJECT 宏时,它就会为这个类生成另外一个包含有元对象支持代码的 C++ 源文件,这个生成的源文件连同类的实现文件一起被编译和连接。
二、功能特性
除了信号与槽机制外,元对象还提供如下一些功能:
-
QObject::metaObject() 函数返回类关联的元对象,元对象类 QMetaObject 包含了访问元对象的一些接口函数,例如 QMetaObject::className() 函数可在运行时返回类的名称字符串。
QObject *obj = new QPushButton; obj->metaObject()->className (); //返回"QPushButton"
-
QObject::inherits(const char *className) 函数判断一个对象实例是否是名称为 className 的类或 QObject 的子类的实例。例如:
QTimer *timer = new QTimer; // QTimer 是 QObject 的子类 timer->inherits ("QTimer"); // 返回 true timer->inherits ("QObject"); // 返回 true timer->inherits ("QAbstractButton");//返回 false,不是 QAbstractButton 的子类
-
QObject::tr() 和 QObject::trUtf8() 函数可翻译字符串,用于多语言界面设计,后续章会专门介绍多语言界面设计。
-
QObject::setProperty() 和 QObject::property() 函数用于通过属性名称动态设置和获取属性值。
-
QMetaObject::newInstance() 函数创建类的一个新的实例。
-
对于 QObject 及其子类,还可以使用 qobject_cast() 函数进行动态投射,qobject_cast()方法的功能类似于标准C++的dynamic_cast(),但qobject_cast()不需要RTTI的支持。,例如:
//假设MyWidget继承自QWidget,同时也声明了Q_OBJECT宏, QObject *obj = new MyWidget; //QObject类型的变量obj实际上指向一个MyWidget对象,进行类型转换: QWidget *widget = qobject_cast<QWidget *>(obj);//得到widget //如果 QLabel *label = qobject_cast<QLabel *>(obj);// label is 0 //QLabel的转型会失败,指针会被设置为0。这样使得我们可以在运行时根据对象类型,对不同类型的对象进行不同的处理: if (QLabel *label = qobject_cast<QLabel *>(obj)) { label->setText(tr("label")); } else if (QPushButton *button = qobject_cast<QPushButton *>(obj)) { button->setText(tr("QPushButton")); }
如果我们只是单纯的使用QObject作为基类,不用Q_OBJECT宏和原对象信息,那么信号和槽以及其他这里描述的特性将无法使用。从元对象系统的观点来看,一个没有元对象代码的QObject子类和其最接近的有元对象代码的祖先是等同的。这也就意味着,QMetaObject::className()将不会返回你的类的真实的名字,而是该类某一个祖先的名字。建议:所有QObject的子类都是用Q_OBJECT宏,不管你实际上是否使用信号和槽,以及属性。
三、属性系统
#ifndef OBJECT_H
#define OBJECT_H
class Object : public QObject
{
Q_OBJECT
Q_PROPERTY(int age READ age WRITE setAge NOTIFY ageChanged)
Q_PROPERTY(int score READ score WRITE setScore NOTIFY scoreChanged)
Q_CLASSINFO("Author", "Scorpio")
Q_CLASSINFO("Version", "1.0")
Q_ENUMS(Level)
};
#endif // OBJECT_H
Q_PROPERTY()
在 QObject 的子类中,用宏 Q_PROPERTY() 定义属性,其使用格式如下:
Q_PROPERTY(type name
(READ getFunction [WRITE setFunction] |
MEMBER memberName [(READ getFunction | WRITE setFunction)])
[RESET resetFunction]
[NOTIFY notifySignal]
[REVISION int]
[DESIGNABLE bool]
[SCRIPTABLE bool]
[STORED bool]
[USER bool]
[CONSTANT]
[FINAL])
- Type:属性的类型
- Name:属性的名称
- READ getFunction:属性的访问函数
- WRITE setFunction:属性的设置函数
- RESET resetFunction:可选,用于指定一个设置属性缺省值的函数
- NOTIFY notifySignal:,可选,用于属性发生变化的地方发射的notifySignal信号
- REVISION int:属性的版本,属性暴露到QML中
- DESIGNABLE bool:属性在GUI设计器Qt Designer中是否可见,默认为true
- SCRIPTABLE bool:属性是否可以被脚本引擎访问,默认为true
- STORED bool:表示是否应将属性视为独立存在或取决于其他值,大多数属性都是存储的(默认为true),但例如,QWidget::minimumWidth()存储了false,因为它的值只是从属性QWidget::minimumSize()的宽度组件中获取的。
- USER bool:属性是否可编辑的属性。通常,每个类只有一个用户属性(默认为false)。 例如QAbstractButton::checked是按钮的用户可编辑属性。
- CONSTANT:标识属性的值是常量,值为常量的属性没有WRITE、NOTIFY
- FINAL:标识属性不会被被子类重载
Q_PROPERTY 宏定义一个返回值类型为 type,名称为 name 的属性,用 READ、WRITE 关键字定义属性的读取、写入函数,还有其他的一些关键字定义属性的一些操作特性。属性的类型可以是 QVariant 支持的任何类型,也可以用户自定义类型。
Q_CLASSINFO()
可以为类的元对象定义“名称——值”;
用 Q_CLASSINFO() 宏定义附加类信息后,可以通过元对象的一些函数获取类的附加信息,如 classlnfo(int) 获取某个附加信息,函数原型定义如下:
QMetaClassInfo QMetaObject::classInfo(int index) const
返回值是 QMetaClassInfo 类型,有 name() 和 value() 两个函数,可获得类附加信息的名称和值。
Q_INVOKABLE
Q_INVOKABLE宏用于定义一个成员函数可以被元对象系统调用,Q_INVOKABLE宏必须写在函数的返回类型之前。如下:
Q_INVOKABLE void invokableMethod();
invokableMethod()函数使用了Q_INVOKABLE宏声明,invokableMethod()函数会被注册到元对象系统中,可以使用 QMetaObject::invokeMethod()调用。
Q_INVOKABLE与QMetaObject::invokeMethod均由元对象系统唤起。
参见 https://blog.51cto.com/u_9291927/2070348
小白发文,不喜勿喷