Qt元对象(Meta-Object)系统与反射

反射

-在计算机科学中,反射是指计算机程序在运行时(Run time)可以访问、检测和修改它本身状态或行为的一种能力。[1]用比喻来说,反射就是程序在运行的时候能够“观察”并且修改自己的行为。

要注意术语“反射”和“内省”(type introspection)的关系。内省(或称“自省”)机制仅指程序在运行时对自身信息(称为元数据)的检测;反射机制不仅包括要能在运行时对程序自身信息进行检测,还要求程序能进一步根据这些信息改变程序状态或结构。

C++的反射

C++的标准语法是不提供反射的特性的,不过随着C++17的定稿,估计这个关键词不会加到标准中了。不过这个我们可以用template来实现,这次就不写template了。今天主要是讲的是Qt。

Qt的反射

Qt最大的特点就是增加了moc的过程,个人理解,Qt扩展了C++的语法,以及增强了自己的基本库。

Meta Object System is a part of Qt framework core provided to support Qt extensions to C++ like signals/slots for inter-object communication, run-time type information, and the dynamic property system.[1]
Architecture
The Meta object system consists of 3 things: QObject class, Q_OBJECT macro and a tool called moc (Meta-Object Compiler). QObject is the base class for all Qt classes, Q_OBJECT macro is used to enable meta-object features in classes and finally moc is a preprocessor that changes Q_OBJECT macro instances to C++ source code to enable meta object system mechanism in the class in which it is used.[2]
Using the meta object system has brought some criticism. In Qt documentation, several reasons have been given for the use of the meta object system, including benefits of code generation, dynamism of GUIs, automatic binding to scripting languages, not adding limitations and also reasonable performance in signal/slot implementation with moc.[3] There are some efforts to make Qt needless of a preprocessor. These efforts include re-implementing Qt moc using libclang.[4]

moc可以理解将Qt中的一些关键词,比如Q_Object ,Q_PROPERTY等转化为c++的基本语法,所以我们在编译Qt的工程时,首先要qmake->make。

个人认为Qt有两个我比较看重的特点。

  • STL基础库的扩展。
  • C++基本语法与特性的扩展。

尤其是基本语法的扩展,比如信号槽,元对象系统,让C++一个静态语言有了动态语言的特性(当然你也可以用template来实现,但是这玩意儿一般人又用不起,而且写起来也比较恶心)。这一点我就可以吹爆了。

下边开始讲Qt的反射。Qt的反射是基于Qt的元对象系统的。当然Qt还不能做到像java那样通过类名来创建一个对象,这个需要我们自己写一个工厂模式。个人认为,除了这一点,与java中的反射没有啥区别了。都可以动态的去访问其成员变量,成员函数,以及设置属性。当然必须加上Qt自己的语法。

举个栗子

//1 .继承 QObject
class TestObject : public QObject
{
    Q_OBJECT // 2.声明Q_OBJECT
    Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChange) //3. Q_PROPERTY 注册成员变量
    Q_PROPERTY(QString text MEMBER m_text NOTIFY textChange) //4. 注册的成员变量能够响应自定义的signals textChange
public:
    TestObject(QObject* parent);
    ~TestObject();
    void init();
    //------
    Q_INVOKABLE QString text(); //5.注册类的成员函数
    Q_INVOKABLE void setText(const QString& strText); //5.注册类的成员函数
    QString m_text; //类的成员变量
signals:
    void textChange(); //自定义的signals
public slots:
    void textslot(){qDebug()<<"textslot"<<endl;} //自定义的signals响应的槽函数
};

//cpp
TestObject::TestObject(QObject* parent) : QObject (parent)
{
    this->setObjectName("TestObject");
    connect(this, SIGNAL(textChange()),this, SLOT(textslot()));
}
TestObject::~TestObject()
{
}
void TestObject::init()
{
    qDebug()<<"*********************"<<endl;
    qDebug()<<"init"<<endl;
}
QString TestObject::text()
{
    return m_text;
}
void TestObject::setText(const QString& strText)
{
    if (m_text == strText)
        return;
    m_text = strText;
//    emit textChange(); //有了第四条这个语句已经不需要了。
}

这里看调用方法

    TestObject* obj = new TestObject(this);  // new一个对象

    qDebug()<<obj->objectName()<<endl; //输出对象的名字
    // custom object property
    obj->setProperty("text", "hahaha");    //设置对象的属性
    qDebug()<<obj->property("text").toString()<<endl; //输出对象的属性

    //得到注册的类成员函数
    qDebug()<<"begin--------------------custom class method"<<endl;
    const QMetaObject* mobj = obj->metaObject();

    qDebug()<<mobj->methodCount()<<endl;
    for(int i = 0; i < mobj->methodCount(); i++)
    {
        QMetaMethod mMethod = mobj->method(i);
        QByteArray byteArray = mMethod.name();
        //输出函数类型与函数名称
        qDebug()<<mMethod.typeName()<<"->"<<QString(byteArray)<<endl;
    }
    qDebug()<<"end----------------------custom class method"<<endl;

    //调用注册的成员函数,通过Q_RETURN_ARG来获取返回值
    qDebug()<<"begin    QMetaObject::invokeMethod"<<endl;
    QString invokeString;
    //调用类的成员函数
    QMetaObject::invokeMethod(obj, "text", Qt::DirectConnection, Q_RETURN_ARG(QString, invokeString));
    qDebug()<<invokeString<<endl;
    qDebug()<<"end            QMetaObject::invokeMethod"<<endl;

    // 再次设置text值,可以响应这个信号,可以参考4
    obj->setProperty("text", "luelueluelue");

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

Qt通过类名来实现真正的反射

#include <QByteArray>
#include <QMetaObject>
#include <QHash>

#ifndef OBJECTFACTORY_H
#define OBJECTFACTORY_H

class ObjectFactory
{
public:
    template<typename T>
    static void registerClass()
    {
        constructors().insert( T::staticMetaObject.className(), &constructorHelper<T> );
    }

    static QObject* createObject( const QByteArray& className, QObject* parent = NULL )
    {
        Constructor constructor = constructors().value( className );
        if ( constructor == NULL )
            return NULL;
        return (*constructor)( parent );
    }

private:
    typedef QObject* (*Constructor)( QObject* parent );

    template<typename T>
    static QObject* constructorHelper( QObject* parent )
    {
        return new T( parent );
    }

    static QHash<QByteArray, Constructor>& constructors()
    {
        static QHash<QByteArray, Constructor> instance;
        return instance;
    }
};

#endif // OBJECTFACTORY_H

下边是使用方法。todo ,这个东西应该写成单例模式的。

//使用方法
    ObjectFactory fac;
    fac.registerClass<TestObject>();
    qDebug()<<"begin-------------------------------"<<endl;
    TestObject* object = qobject_cast<TestObject*>(fac.createObject( "TestObject" , this));
    object->setText("template factory");
    qDebug()<<object->text()<<endl;

http://www.cryfeifei.cn/395.html

原文地址:https://www.cnblogs.com/findumars/p/11984917.html

时间: 2024-10-13 05:22:53

Qt元对象(Meta-Object)系统与反射的相关文章

Qt元对象系统源码解析

Qt元对象系统源码解析 https://blog.51cto.com/9291927/2070348 一.Qt元对象系统简介 1.元对象系统简介 Qt 的信号槽和属性系统基于在运行时进行内省的能力,所谓内省是指面向对象语言的一种在运行期间查询对象信息的能力, 比如如果语言具有运行期间检查对象型别的能力,那么是型别内省(type intropection)的,型别内省可以用来实施多态.C++的内省比较有限,仅支持型别内省, C++的型别内省是通过运行时类型识别(RTTI)(Run-Time Typ

什么是Qt元对象系统

Qt元对象系统,即meta object system(mos),提供了大家熟知的用于对象间信息传递的信号与槽机制,运行时类型信息和动态属性系统. mos基于三件法宝: 一是QObject类,是所有Qt对象的基类,可以很好的使用mos. 二是Q_OBJECT宏,在类private部分声明,用于激活mos特性,例如动态属性.信号与槽. 三是元对象编译器,即meta object compiler(moc),为QObject的派生类提供了必要的代码以实现mos特性.例如Example.h中声明了Ex

QT元对象系统简介

 QT元对象系统   qt的主要成就之一就是使用了一种机制对C++进行了扩展,并且使用这种机制创建了独立的软件组件,这些组件可以绑定在一起,但任何一个组件对于它所要连接的组件的情况一无所知,这种机制就称为元对象系统,它提供了关键的两个技术,信号和槽,以及内省.     内省功能对于实现信号和槽是必须的,并且容许开发人员在运行时获取有关QObject子类的"元信息",包括一个含有对象的类名以及它所支持的信号和槽的列表,这一机制也支持属性和文本翻译,并且为Qtscript模块奠定了基础,标

Qt 元对象系统(Meta-Object System)

(转自:http://blog.csdn.net/aladdina/article/details/5496891) Qt的元对象系统基于如下三件事情: 类:QObject,为所有需要利用原对象系统的对象提供了一个基类. 宏:Q_OBJECT,通常可以声明在类的私有段中,让该类可以使用元对象对象的特性,比如动态属性,信号和槽. 编译器:元对象编译器(moc)为每个QObject子对象自动生成必要的代码来实现元对象特性. moc工具会读入C++的源文件,如果它发现了一个或者多个声明了Q_OBJEC

Qt笔记——元对象系统

Qt元对象系统提供了对象间的通信机制:信号和槽.以及执行类形信息和动态属性系统的支持.是标注C++的一个扩展,它使得Qt可以更好的实现GUI图形用户界面编程.Qt的元对象系统不支持C++模板.虽然模板扩展了C++的功能,可是元对象提供了模板无法提供的一些特性. Qt的元对象基于三个事实: 1. 基类Q_OBJECT,不论什么想使用元对象系统功能的类必须继承自QOBject; 2. Q_OBJECT宏,Q_OBJECT宏必须出如今类的私有声明区,以完毕元对象的特性. 3. 元对象编译器(Meta-

元对象、 属性 和 反射编程

所谓反射,就是指对象成员的自我检查,使用反射编程就可以编写出通用的操作,可对具有各种不同结构的类进行操作; Qt使用通用的值存储器QVariant,就可以按照一种统一的方式来对基本类型和其他普通类型进行操作; QMetaObject  ---- 元对象模式 元对象,就是描述另一个对象结构的对象; QMetaObject是元对象模式(MetaObject Pattern)的一个Qt实现,他提供一个QObject对象拥有的属性和方法的信息.      一个拥有元对象的类就可以支持反射,这是一个许多面

QT元编程----Q_ENUMS

头文件中定义枚举类型并设置Q_ENUMS #ifndef TEST_H#define TEST_H #include <QObject>#include <QMetaEnum> class Test : public QObject{ Q_OBJECT Q_ENUMS(TestType) //[1] public: explicit Test(QObject *parent = nullptr); enum TestType { TEST_ONE, TEST_TWO, TEST_T

Qt Meta Object System-元对象系统

Qt Meta Object System-元对象系统 元对象系统的构成 QObject为所有需要利用元对象系统的对象提供一个基类. Q_OBJECT宏,在类的声明体内激活meta-object功能,比如动态属性.信号和槽. Meta Object Compiler(MOC),为每个QObject派生类生成代码,以支持meta-object功能. QObject定义了从一个QObject对象访问meta-object功能的接口,Q_OBJECT宏用来告诉编译器该类需要激活meta-object功

深入了解Qt(二)之元对象系统(Meta-Object System)

深入了解Qt主要内容来源于Inside Qt系列,本文做了部分删改,以便于理解.在此向原作者表示感谢! 在Qt Meta Object System-元对象系统这篇文章中,从底层实现的源码剖析了元对象系统的机制,在这里就做一些补充. Meta Object System的设计基于以下几个基础设施: QObject类,作为每一个需要利用元对象系统的类的基类.也就是说只有继承QObject类才能使用MOS. Q_OBJECT宏,定义在每一个类的私有数据段,用来启用元对象功能,比如,动态属性.信号和槽