qt的反射用法(新版本)

qt的反射用法,直接上代码

Animal.h

#ifndef ANIMAL_H
#define ANIMAL_H
#include<QString>
#include<QObject>

class Animal : public QObject{
    //Q_OBJECT,这个为什么注释,因为后面发现一只提示方法重复定义,所以取消父类的标记
public:
    explicit Animal(QObject *parent = 0);
    //Animal();
    virtual QString getName() const=0;

    virtual int getAge() const=0;
};


#endif // ANIMAL_H

Animal.cpp

#include "Animal.h"


Animal::Animal(QObject *parent) : QObject(parent)
{
}

Dog.h

#ifndef DOG_H
#define DOG_H
#include"Animal.h"
//#include<QString>
//#include<QObject>

class Dog : public Animal{
    Q_OBJECT
    Q_PROPERTY (QString name READ getName WRITE setName);
    Q_PROPERTY (int age READ getAge WRITE setAge);
    Q_ENUMS(Type);
public:
    Q_INVOKABLE Dog();
    Q_INVOKABLE void setAge(const int age);
    Q_INVOKABLE void setName(const QString& name);
    Q_INVOKABLE QString getName() const;
    Q_INVOKABLE int getAge() const;
    enum Type{
        ERHA,SHAMOYE,ALASIJI,TIANYUAN
    };

    Q_INVOKABLE Type getType() const;
    Q_INVOKABLE void setType(Type suit);
    QString getTypeString();

private:

    Type type;
    QString name;
    int age;
};

Dog.cpp

#include "Dog.h"

Dog::Dog():Animal(nullptr){}

void Dog::setName(const QString &name){
    this->name=name;
}

QString Dog::getName() const{
    return this->name;
}

int Dog::getAge() const{
    return this->age;
}

Dog::Type Dog::getType() const{
    return this->type;
}

void Dog::setType(Dog::Type type){
    this->type=type;
}

QString Dog::getTypeString(){
    QString name;
    switch (this->type) {
    case ERHA:name="ERHA";
    case SHAMOYE:name="SHAMOYE";
    case ALASIJI:name="ALASIJI";
    case TIANYUAN:name="TIANYUAN";
    default:
        name="TIANYUAN";
    }
    return name;
}

void Dog::setAge(const int age){
    this->age=age;
}

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "Dog.h"
#include <QDebug>

#include <QQmlContext>

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    //注册
    int typeId= qRegisterMetaType<Dog*>();
    const QMetaObject *metaObj = QMetaType::metaObjectForType(typeId);

    //实例化dog
    QObject *obj = metaObj->newInstance();
    //获取属性的个数
    int propertyCount = metaObj->propertyCount();
    //获取方法的个数
    int methodCount = metaObj->methodCount();

    //输出属性的名字
    for(int j = 0;j<propertyCount;j++){
        qDebug()<<"propertyName="<< metaObj->property(j).name();

    }
    //输出类和方法的信息
    qDebug()<<"className"<< metaObj->className();
    for(int j = 0;j<methodCount;j++){
        qDebug()<<"methodName="<< metaObj->method(j).name()<<"methodType"<<metaObj->method(j).typeName()<<"methodSignature"<<metaObj->method(j).methodSignature();

    }

    //通过执行set方法给属性赋值
    QMetaObject::invokeMethod( obj, "setName", Qt::DirectConnection,Q_ARG(QString, "阿黄"));
    QMetaObject::invokeMethod( obj, "setAge", Qt::DirectConnection,Q_ARG(int, 3));
    QString name;
    int age=0;
    //get方法取值
    QMetaObject::invokeMethod( obj, "getName", Qt::DirectConnection, Q_RETURN_ARG(QString, name ));
    QMetaObject::invokeMethod( obj, "getAge", Qt::DirectConnection, Q_RETURN_ARG(int, age ));

    qDebug()<<"dogname="<< name<<",dogAge="<<age;
    //直接给属性赋值
    obj->setProperty("name",QVariant("小黑"));
    obj->setProperty("age",QVariant(4));
    //obj->setProperty("age",4);
    qDebug()<<"dogname="<< obj->property("name").toString()<<",dogAge="<<obj->property("age").toInt();
    //dog向上造型
    Animal *dog = qobject_cast<Dog*>(obj);
    qDebug()<<"dogname="<< dog->getName()<<",dogAge="<<dog->getAge();


    //加载qml
    QQmlApplicationEngine engine;
    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);

    //绑定一下dog
    engine.rootContext()->setContextProperty("dog",dog);
    engine.load(url);
    return app.exec();
}

main.qml

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
Window {
    visible: true
    width: 400
    height: 210
    color: "#ffffff"
    title: qsTr("QuickControlsDemo")

    Text {
        id: text1
        x: 47
        y: 35
        width: 80
        height: 30
        text: qsTr("用户名:")
        horizontalAlignment: Text.AlignRight
        verticalAlignment: Text.AlignVCenter
        font.pixelSize: 14
    }

    TextField  {
        id: textField1
        x: 137
        y: 35
        width: 200
        height: 30
        placeholderText: qsTr("请输入用户名")
    }

    Text {
        id: text2
        x: 47
        y: 85
        width: 80
        height: 30
        text: qsTr("密  码:")
        verticalAlignment: Text.AlignVCenter
        font.pixelSize: 14
        horizontalAlignment: Text.AlignRight
    }

    TextField {
        id: textField2
        x: 137
        y: 85
        width: 200
        height: 30
        //echoMode: 2
        placeholderText: qsTr("请输入密码")
        onTextChanged: {
            textField1.text=dog.getName()
        }
    }

     Button {
        id: button1
        x: 71
        y: 145
        width: 116
        height: 36
        text: qsTr("登 录")
        onClicked: {
        textField2.text=dog.getAge()
        }
    }

    Button {
        id: button2
        x: 224
        y: 145
        width: 110
        height: 36
        text: qsTr("取 消")
    }
}


输出结果

propertyName= objectName
propertyName= name
propertyName= age
className Dog
methodName= "destroyed" methodType void methodSignature "destroyed(QObject*)"
methodName= "destroyed" methodType void methodSignature "destroyed()"
methodName= "objectNameChanged" methodType void methodSignature "objectNameChanged(QString)"
methodName= "deleteLater" methodType void methodSignature "deleteLater()"
methodName= "_q_reregisterTimers" methodType void methodSignature "_q_reregisterTimers(void*)"
methodName= "setAge" methodType void methodSignature "setAge(int)"
methodName= "setName" methodType void methodSignature "setName(QString)"
methodName= "getName" methodType QString methodSignature "getName()"
methodName= "getAge" methodType int methodSignature "getAge()"
methodName= "getType" methodType Type methodSignature "getType()"
methodName= "setType" methodType void methodSignature "setType(Type)"
dogname= "阿黄" ,dogAge= 3
dogname= "小黑" ,dogAge= "4"
dogname= "小黑" ,dogAge= 4

总结:

1.整体用法没有什么,都是一些api,主要是用Q_PROPERTY,Q_INVOKABLE标记

2.和java的反射相比体验差了一大截,看了一下这个其实是moc编译生成了中间类

3.本人所用qt版本5.14,版本不一样可能跑不起来,百度的很多版本比较老了,注意下

完毕。

<think>好的,我现在需要回答用户关于RTTR反射库以及它如何与Qt结合使用的问题。首先,我得先理解RTTR反射库的基本概念和用途。反射库的主要作用是允许程序在运行时检查和操作类型信息,比如类、方法、属性等。这对于需要动态处理对象的情况非常有用,比如序列化、反序列化、脚本绑定等。 接下来,我需要确认RTTR的具体功能和特点。根据之前的了解,RTTR支持C++,并且不需要在代码中添加额外的宏或者使用特定的预处理工具,这是它的优势之一。用户可能想知道RTTR与Qt的结合使用,Qt本身有自己的元对象系统,尤其是在信号槽机制和属性系统方面,所以需要比较两者的异同,以及如何互补使用。 用户的问题可能还涉及到如何在Qt项目中集成RTTR,比如是否会有冲突,或者如何利用RTTR来增强Qt的功能。例如,Qt的元对象系统在编译时生成,而RTTR可以在运行时提供更多的灵活性。可能需要举一些具体的例子,比如如何在Qt中使用RTTR进行动态类型创建,或者在Qt的UI元素中动态绑定属性。 另外,需要注意RTTR和Qt结合时的潜在问题,比如内存管理、类型注册的步骤,以及可能的性能影响。需要确保提供的步骤是清晰的,让用户能够按照指导进行操作。 可能还需要检查是否有最新的RTTR版本和Qt版本之间的兼容性问题,确保提供的建议是当前有效的。同时,用户可能对实际应用场景感兴趣,比如游戏开发中的对象序列化,或者插件系统的动态加载,这些都可以作为例子来说明RTTR与Qt结合的实际好处。 最后,要确保回答结构清晰,分点说明RTTR的功能、与Qt的结合方法,以及具体的使用示例,让用户能够逐步理解和应用。</think>RTTR(Run Time Type Reflection)是一个开源的C++运行时类型反射库,允许在运行时动态获取和操作类型信息(如类、属性、方法等)。它弥补了C++原生缺乏反射支持的缺陷,常用于序列化、脚本绑定、数据检查、动态GUI生成等场景。 --- ### **RTTR 的核心功能** 1. **类型注册**:通过代码注册类、属性、方法、枚举等元信息。 2. **动态类型操作**:运行时创建对象、调用方法、访问属性。 3. **跨平台支持**:不依赖编译器特性(如RTTI),纯模板实现。 4. **无侵入性**:不需要修改已有类的代码(通过外部注册实现)。 --- ### **为何与 Qt 结合?** Qt 自身有一套基于宏(如`Q_OBJECT`)的元对象系统(Meta-Object System),支持信号槽、属性系统(`Q_PROPERTY`)和动态类型(`qobject_cast`)。但 Qt反射功能有限,无法直接获取所有类成员。 **结合 RTTR 的优势**: - **扩展反射能力**:动态访问非QObject类、标准库类型或第三方库的成员。 - **简化序列化**:结合 Qt 的 JSON/XML 模块,实现复杂对象的自动序列化。 - **动态UI绑定**:自动将对象属性映射到Qt控件(如动态生成属性编辑器)。 --- ### **RTTR 与 Qt 结合使用步骤** #### 1. **注册类型到 RTTR** ```cpp #include <rttr/registration> using namespace rttr; class MyClass { public: int value = 42; void print() { qDebug() << "Value:" << value; } }; // 注册类及其成员 RTTR_REGISTRATION { registration::class_<MyClass>("MyClass") .constructor<>() .property("value", &MyClass::value) .method("print", &MyClass::print); } ``` #### 2. **在 Qt 中动态使用 RTTR** ```cpp // 动态创建对象 variant obj = type::get_by_name("MyClass").create(); if (obj.is_valid()) { // 动态设置属性 property prop = obj.get_type().get_property("value"); prop.set_value(obj, 100); // 动态调用方法 method m = obj.get_type().get_method("print"); m.invoke(obj); } ``` #### 3. **与 Qt 信号槽结合** 若需将 RTTR 方法绑定到 Qt 信号,可通过 Lambda 或中间层适配: ```cpp QObject* adapter = new QObject; QPushButton* button = new QPushButton("Click"); QObject::connect(button, &QPushButton::clicked, [&obj]() { method m = obj.get_type().get_method("print"); m.invoke(obj); }); ``` #### 4. **序列化 Qt 对象** 将 Qt 对象属性通过 RTTR 转换为 JSON: ```cpp QJsonObject serialize(const QObject* obj) { QJsonObject json; const auto metaObj = obj->metaObject(); for (int i = 0; i < metaObj->propertyCount(); ++i) { QMetaProperty prop = metaObj->property(i); json[prop.name()] = QJsonValue::fromVariant(prop.read(obj)); } // 使用 RTTR 补充非 Q_PROPERTY 成员 type t = type::get_by_name(obj->metaObject()->className()); for (auto& prop : t.get_properties()) { if (!json.contains(prop.get_name().data())) { json[prop.get_name().data()] = prop.get_value(obj).to_int(); } } return json; } ``` --- ### **注意事项** - **QObject 派生类**:需确保先通过 Qt 宏(如`Q_OBJECT`)注册,再通过 RTTR 补充反射。 - **性能**:频繁的运行时反射可能影响性能,建议缓存 `type` 和 `method` 对象。 - **内存管理**:RTTR 的 `variant` 不管理对象生命周期,需手动控制或结合 `QSharedPointer`。 --- ### **典型应用场景** - **动态编辑器**:根据类的 RTTR 信息自动生成 Qt 属性面板。 - **游戏引擎**:结合 Qt 编辑器,动态修改 C++ 对象的属性。 - **插件系统**:通过 RTTR 动态加载插件类并调用方法。 通过结合 RTTR 和 Qt,可以显著增强 C++ 项目的动态性和灵活性,尤其适合需要高度可扩展架构的应用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值