zoukankan      html  css  js  c++  java
  • 深入Qt 学习 -- 反射机制(比较简单清楚)

    相对于Java天生的这一特性, C++并不具备;但进入到Qt领域,这一切都变得简单自如了。

    从Qt的元对象系统可知,除了提供信号/槽机制的特性之外,它还提供了以下特性:

    ■ QObject::metaObject()

    返回关联的元对象

    ■ QObject::className()

    在运行时状态下返回类名

    ■ QObject::inherits()

    判断类的继承关系

    ■ QObject::tr()

    QObject::trUtf8()

    提供国际化,翻译字符串

    ■ QObject::setProperty()

    QObject::property()

    通过名称来动态设置和获取属性

    ■ QObject::newInstance()

    创建实例

    其中QObject::className()、QObject::setProperty()和QObject::property()比较吸引眼球,这正是反射机制中的基本功能。建立在Qt的元对象系统的基础上,只要拥有元对象(QMetaObject)的类就支持反射!如何拥有元对象?方法很简单:只需继承于QObject或者它的子类(多重继承的话,QObject类应该放在第一个),在头文件的结构声明中写上Q_OBJECT即可!

    元对象信息

    通过QObject::metaObject()方法, 所有继承于QObject的类可以 返回元对象系统为其生成的metaObject对象。看看QMetaObject提供的一些重要信息:

    ■ QMetaClassInfo

    通过宏Q_CLASSINFO的支持,提供类的附加信息

    ■ QMetaEnum

    Qt特色的枚举对象,支持key和 value之间的互转

    ■ QMetaMethod

    提供类成员函数的元数据

    ■ QMetaProperty

    提供类成员属性的元数据

    根据QMetaObject提供的数据对象,完全可以编写通用的代码来支持反射特性。

    例子:

    声明一个类,继承于QObject

    classReflectionObject : publicQObject

    {

          Q_OBJECT

          Q_PROPERTY(intId READ Id WRITE setId)

          Q_PROPERTY(QString Name READ Name WRITEsetName)

          Q_PROPERTY(QString Address READ Address WRITEsetAddress)

          Q_PROPERTY(PriorityType Level READ Priority WRITEsetPriority)

     

          Q_ENUMS(PriorityType)

     

    public:

          enumPriorityType { High, Low, VeryHigh,VeryLow };

     

          Q_INVOKABLEint Id() {returnm_Id; }

          Q_INVOKABLEQString Name() { returnm_Name; }

          Q_INVOKABLEQString Address() { returnm_Address; }

          Q_INVOKABLEPriorityType Priority() const {returnm_Priority; }

     

          Q_INVOKABLEvoid setId(constint& id) {m_Id = id; }

          Q_INVOKABLEvoid setName(constQString& name) {m_Name = name; }

          Q_INVOKABLEvoid setAddress(constQString& address) {m_Address = address; }

          Q_INVOKABLEvoid setPriority(PriorityType priority) {m_Priority = priority; }

     

    private:

          int         m_Id;

          QString  m_Name;

          QString  m_Address;

     

          PriorityTypem_Priority;

    };

    为了能检测到类成员函数,得在函数前加上一个宏Q_INVOKABLE, 这意味着该函数在元对象系统编译该类时注册该函数,则在运行过程中能被元对象调用。

    经过上述声明,在运行时即可做些操作:

    /*遍历该类的成员: */

    ReflectionObjecttheObject;

    constQMetaObject*theMetaObject =theObject.metaObject();

     

    intmetathodIndex;

    intmetathodCount = theMetaObject->methodCount();

    for(metathodIndex = 0; metathodIndex < metathodCount; ++metathodIndex)

    {

          QMetaMethodoneMethod =theMetaObject->method(metathodIndex);

          qDebug() <<"typeName: " <<oneMethod.typeName();

          qDebug() <<"signature: " <<oneMethod.signature();

          qDebug() <<"methodType: " <<oneMethod.methodType();;

          qDebug() <<"parameterNames: " <<oneMethod.parameterNames() <<" ";

    }

    /*遍历该类的属性: */

    intpropertyIndex;

    intpropertyCount = theMetaObject->propertyCount();

    for(propertyIndex = 0; propertyIndex < propertyCount; ++propertyIndex)

    {

          QMetaPropertyoneProperty =theMetaObject->property(propertyIndex);

          qDebug() <<"name: " << oneProperty.name();

          qDebug() <<"type: " <<oneProperty.type() <<" ";

    }

     

    /*遍历该类的枚举集合*/

    intenumeratorIndex;

    intenumeratorCount = theMetaObject->enumeratorCount();

    for(enumeratorIndex = 0; enumeratorIndex < enumeratorCount; ++enumeratorIndex)

    {

          QMetaEnumoneEnumerator =theMetaObject->enumerator(enumeratorIndex);

     

          intenumIndex;

          intenumCount = oneEnumerator.keyCount();

          for(enumIndex = 0;enumIndex < enumCount; ++enumIndex)

          {

                 qDebug() <<oneEnumerator.key(enumIndex) <<" ==> " <<oneEnumerator.value(enumIndex);

          }

    }

    在这里我们看到QMetaEnum存在key、value配对出现,这必然可以互转,而QMetaEnum确实提供了方式:valueToKey()、keyToValue()。

    通过这个测试能将ReflectionObject这个类的方法和属性完全遍历出来,完成自身的检查,也即反射。

    反射在Qt应用程序中的用途

    在Qt的元对象系统支持下,赋予了C++并不直接拥有的此特性。这样加大了开发应用程序的自由度,尤其在软件工程中强调高内聚低耦合的状态下。

    具体的用例中, 可以通过Qt Designer这个工具来描述(尽管暂不清楚内部是否利用此方法来实现J):

    对于其中的控件,放入到Designer中时,Designer事先并不知道(其实也不需要知道)放入插件的类型、方法和属性。将插件导入时,它可以检测该控件的类型、方法和属性;

    这样在Designer中绘制控件时,遍历该控件的属性, 将这些属性显示在属性窗口中,便于修改;

    在信号/槽对话框编辑时,遍历该控件的属性,提取信号/槽函数,放入对应的编辑区域里;

    http://blog.csdn.net/playstudy/article/details/7861329

  • 相关阅读:
    [UE4]使用C++重写蓝图,SpawnObject根据类型动态创建UObject
    [UE4]在C++中使用中文变量和中文注释
    [UE4]The global shader cache file missing 运行错误解决办法
    [UE4]自定义结构体、类、数据表
    [UE4]使用UFUNCTION注意事项
    [UE4]一个好用的虚幻4插件,根据资源名称动态加载资源,GetCurrentLeveName(获得当前地图名称)
    [UE4]小地图UI放在哪里创建合适?
    [UE4]动态改变相机OrthWidh、关掉阴影
    [UE4]迁移小地图到其他工程
    [UE4]正交
  • 原文地址:https://www.cnblogs.com/findumars/p/8030601.html
Copyright © 2011-2022 走看看