Qt元对象系统

Qt的元对象系统提供了对象之间通信的信号与槽机制、运行时类型信息和动态属性系统。元对象系统由以下三个基础组成。

  • QObject类是所有使用元对象系统的类的基类。
  • 在一个类的private部分声明Q_OBJECT宏,使得类可以使用元对象的特性,如动态属性、信号与槽。
  • MOC(元对象编译器)为每一个QObject的子类提供必要的代码来实现元对象系统的特性。

构建项目时,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<QWidget*>(obj);

从QObject到QWidget的投射是成功的,因为obj实际是QMyWidget类,是QWidget的子类。也可以将其成功投射为QMyWidget,即:

QMyWidget *myWidget=qobject_cast<QMyWidget*>(obj);

投射为QMyWidget是成功的,因为qobject_cast()并不区分Qt内建的类型和用户自定义类型。

Qt中的反射

#ifndef TESTOBJECT_H
#define TESTOBJECT_H
#include <QObject>

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="<<mobj->methodCount();
    for(int i=0;i<mobj->methodCount();i++)
    {
       QMetaMethod method= mobj->method(i);
       qDebug()<<"typeName="<<method.typeName()<<"->"<<"name="<<method.name();
    }

    QString invokeString;
    QMetaObject::invokeMethod(obj,"text",Qt::DirectConnection,Q_RETURN_ARG(QString,invokeString));
    qDebug()<<invokeString;

看上面的代码,C++能够随时获取当前类的成员变量与成员函数以及调用,反射在写GUI的时候是非常有用的。也就是我们可以随时获取当前对象的任何我们想要的属性以及想要调用的函数。静态语言有了动态语言的特性,这就是Qt强大的地方。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值