Qt 反射机制实现,通过类名创建对象

138 篇文章 199 订阅

概述

首先说一下什么是反射:

反射是指程序在运行时动态获取对象属性与方法的一种机制,即编译器需要将类型信息(属性类型与偏移地址以及成员函数的地址等信息)编译到程序文件中,当程序运行时将这些信息加载到内存中去,做到运行时只根据对象的地址或引用就可以获取到对象的类型信息,从而利用这些信息达到修改或重建对象的目标。

再简单一点说,就是可以通过类名称来创建一个类对象,这在Java和Object-C中是原生支持的,所以实现起来非常简单,但是C++就不支持了,如果想要用到反射机制,那就得自己实现。


文中Demo下载


反射的作用

在计算机编程语言中,反射机制可以用来:

  • 获取类型的信息,包括属性、方法
  • 动态调用方法
  • 动态构造对象
  • 从程序集中获得类型

反射的缺点

性能:反射可以理解成是一种解释操作,这个过程总是要慢于直接调用的。当然,性能问题的程度是可以控制的,如果程序在很少涉及的地方使用,性能将不会是一个问题。适用于性能不敏感的部分。
反射模糊了程序内部实际发生的事情,会比直接代码更加复杂。增加了理解代码的难度。
缺点不能掩饰其优点,针对不同的场景使用合理的技术才是最高境界。

反射的使用场景

  • 序列化(Serialization), in custom binary format or in XML, JSON, XDR, etc.
  • 反序列化(Deseriallization),从序列中重建了对象实例与关系。
  • 远程方法调用, remote procedure calls (RPC) / remote method invocation (RMI)。
  • 对象/关系数据映射(O/R mapping)eg. Hibernate,作为虚拟对象数据库,实现数据和对象的持久化。
  • 数据绑定(Data Binding),实现数据对象与关系的可视化,与交互控制调整。
  • 某些软件设计模式的自动化和半自动化实现。

如何实现

其实实现也不难的,在创建对象之前,需要先将要类注册,注册的目的是为了将类名及函数指针做个绑定,采用Hash表来实现,创建对象的时候,直接从hash表中取出函数指针并创建对象即可。
由于我们使用Qt对象来实现,那取类名可以直接用元对象系统的staticMetaObject.className()来获取。

话不多说,直接上代码:

creflectclass.h

#include <QObject>

template<typename L>  //用于反射传父类参数
class CReflectClass
{
public:
	//首先要注册创建的类
    template<typename T>
    static void registerClass()
    {
        //&constructorHelper<T>其实是获取创建的函数指针,核心功能。
        constructors().insert(T::staticMetaObject.className(), &constructorHelper<T>);
    }
    static QObject *createObject(const QByteArray& className,L* parent = nullptr)
    {
        Constructor constructor = constructors().value(className);
        if (constructor == nullptr ){
            return nullptr;
        }
        return (*constructor)(parent);//执行new T函数,创建对应实例
    }
private:
    typedef QObject *(*Constructor)(L* parent);
    template<typename T>
    static QObject *constructorHelper(L* parent)
    {
        if(parent)
            return new T(parent);
        else {
            return new T();
        }
    }
    static QHash<QByteArray, Constructor> &constructors()
    {
        static QHash<QByteArray, Constructor> instance;
        return instance;
    }
};

测试调用:

#include "widget.h"
#include "ui_widget.h"
#include "creflectclass.h"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    //注册类
    CReflectClass<Widget>::registerClass<ClassA>();
    CReflectClass<Widget>::registerClass<ClassB>();

    //创建对象
    auto a = static_cast<ClassA*>(CReflectClass<Widget>::createObject("ClassA",this));
    a->test();
    auto b = CReflectClass<Widget>::createObject("ClassB",this);
}

Widget::~Widget()
{
    delete ui;
}

ClassB::ClassB(QObject *parent):
    QObject(parent)
{
    qDebug() << __FUNCTION__ ;
}

ClassA::ClassA(QObject *parent):
    QObject(parent) {
    qDebug() << __FUNCTION__ ;
}

void ClassA::test()
{
    qDebug() << __FUNCTION__;
}


文中Demo下载


参考文档:
https://zhuanlan.zhihu.com/p/414069595

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

luoyayun361

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值