Qt的元对象系统提供了对象之间通信的信号与槽机制、运行时类型信息和动态属性系统。元对象系统由以下三个基础组成。
构建项目时,MOC工具读取C++的源文件,当它发现类的定义里有Q_OBJECT宏时,它就会为这个类生成另一个包含有元对象支持代码的C++源文件,这个生成的源文件连同类的实现文件一起被编译和连接。、
除了信号与槽机制外,元对象还提供如下一些功能。
■ QObject::metaObject() | 返回关联的元对象 |
---|---|
■ QObject::className() | 在运行时状态下返回类名 |
■ QObject::inherits() | 判断类的继承关系 |
■ QObject::tr()和QObject::trUtf8() | 提供国际化,翻译字符串 |
■ QObject::setProperty()QObject::property() | 通过名称来动态设置和获取属性 |
■ QObject::newInstance() | 创建实例 |
注意:元对象系统的操作通常是线程安全的,比如元对象是在编译期生成的静态只读实例。然而,如果元对象在被程序动态修改了(如通过 QQmlPropertyMap),应用需要显示地同步对相关对象的访问。
对于QObject及其子类,还可以使用qobject_cast()函数进行动态投射。例如,假设QMyWidget是QWidget的子类并且在类定义中声明了Q_OBJECT宏。创建实例使用下面的语句:
QObject* obj=new QMyWidget;
变量obj定义为QObject指针,但它实际指向QMyWidget类,所以可以正确投射为QWidget,即:
QWidget *widget=qobject_cast(obj);
从QObject到QWidget的投射是成功的,因为obj实际是QMyWidget类,是QWidget的子类。也可以将其成功投射为QMyWidget,即:
QMyWidget *myWidget=qobject_cast(obj);
投射为QMyWidget是成功的,因为qobject_cast()并不区分Qt内建的类型和用户自定义类型。
#ifndef TESTOBJECT_H
#define TESTOBJECT_H
#include
class TestObject : public QObject//继承QObject
{
Q_OBJECT//声明Q_OBJECT宏
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged);//Q_PROPERTY注册成员变量
Q_PROPERTY(QString text MEMBER m_text NOTIFY textChanged);//注册成员变量能够响应自定义的signal textChanged
public:
explicit TestObject(QObject *parent = nullptr);
~TestObject();
void Init();
Q_INVOKABLE QString text();//注册类的成员函数
Q_INVOKABLE void setText(const QString& strText);//注册类的成员函数
QString m_text;//类的成员变量
signals:
void textChanged();//自定义signals
public slots:
void textslot();
};
#endif // TESTOBJECT_H
#include "testobject.h"
TestObject::TestObject(QObject *parent)
: QObject{parent}
{
this->setObjectName("TestObject");
connect(this,&TestObject::textChanged ,this,&TestObject::textslot);
}
TestObject::~TestObject()
{
}
void TestObject::Init()
{
qDebug("*****Init*****");
}
QString TestObject::text()
{
return m_text;
}
void TestObject::setText(const QString &strText)
{
if(m_text==strText)
return;
m_text=strText;
}
void TestObject::textslot()
{
qDebug("textChangedSlot");
}
TestObject *obj=new TestObject();
qDebug("objectName="+obj->objectName().toLatin1());//输出对象的名字
obj->setProperty("text","Hahaha");//设置对象的属性
qDebug("text="+obj->property("text").toString().toLatin1());//输出对象的属性
const QMetaObject* mobj=obj->metaObject();
qDebug()<<"methodCount="<methodCount();
for(int i=0;imethodCount();i++)
{
QMetaMethod method= mobj->method(i);
qDebug()<<"typeName="<"<<"name="<
看上面的代码,C++能够随时获取当前类的成员变量与成员函数以及调用,反射在写GUI的时候是非常有用的。也就是我们可以随时获取当前对象的任何我们想要的属性以及想要调用的函数。静态语言有了动态语言的特性,这就是Qt强大的地方。