1.什么是反射?
反射是指程序在运行时动态获取对象属性与方法的一种机制,即编译器需要将类型信息(属性类型与偏移地址以及成员函数的地址等信息)编译到程序文件中,当程序运行时将这些信息加载到内存中去,做到运行时只根据对象的地址或引用就可以获取到对象的类型信息,从而利用这些信息达到修改或重建对象的目标。
2.反射的作用?
- 获取类型的信息,包括属性、方法
- 动态调用方法
- 动态构造对象
- 从程序集中获得类型
3.反射的缺点
性能:反射可以理解成是一种解释操作,这个过程总是要慢于直接调用的。当然,性能问题的程度是可以控制的,如果程序在很少涉及的地方使用,性能将不会是一个问题。适用于性能不敏感的部分。
反射模糊了程序内部实际发生的事情,会比直接代码更加复杂,增加了理解代码的难度。
缺点不能掩饰其优点,针对不同的场景使用合理的技术才是最高境界。
代码区:
ReflectCreateObject.h
#pragma once
#include <QtWidgets/QWidget>
#include <QObject>
#include <QDebug>
#include <QPushButton>
#include "ui_ReflectCreateObject.h"
class ReflectCreateObject : public QWidget
{
Q_OBJECT
public:
/*反射来创建对象,需要把构造函数用 Q_INVOKABLE 进行标记。*/
Q_INVOKABLE ReflectCreateObject(QWidget *parent = Q_NULLPTR) : QWidget(parent) { ui.setupUi(this); }
~ReflectCreateObject() {}
/*通过 Q_PROPERTY 定义类的属性,可以获取使用反射读写对象数据的能力*/
Q_PROPERTY(QString name READ getName WRITE setName)
/*需要使用反射调用的方法要用 Q_INVOKABLE 进行标记。*/
Q_INVOKABLE void func() { qDebug() << "hello world"; }
QString getName() const { return name; }
void setName(const QString& m_name) { name = m_name; }
private:
Ui::ReflectCreateObjectClass ui;
int id;
QString name;
};
//Q_DECLARE_METATYPE(ReflectCreateObject)
ToolRegister.h
#pragma once
#include "ReflectCreateObject.h"
#include <QObject>
#include <QDebug>
#include <QMetaType>
#include <QMetaObject>
class ToolRegister : public QWidget
{
Q_OBJECT
public:
explicit ToolRegister(QWidget* parent = nullptr) : QWidget(parent)
{
//把自定义类型注册到元对象系统中
qRegisterMetaType<ReflectCreateObject*>("ReflectCreateObject&");
auto getObjByName = [&](const QString & className)
{
/*QMetaType支持的内置类型(QT内置类型都已经注册enum QMetaType::Type,enum QMetaType::Type从0开始
其中 0 为UnknowType, 1024为用户自定义类型起始位置。):*/
int type = QMetaType::type(className.toStdString().c_str());
/*通过用户自定义类型枚举值获取元对象*/
const QMetaObject* metaObj = QMetaType::metaObjectForType(type);
/*通过自定义类型构造该类的一个新实例。*/
if (!instance)
{
instance = metaObj->newInstance();
return instance;
}
else
{
return instance;
}
};
/*ReflectCreateObject* widget = qobject_cast<ReflectCreateObject*>(getObjByName("ReflectCreateObject*"));
QScopedPointer<ReflectCreateObject> sp(widget);*/
/*通过;类名获取实例对象*/
QObject* demo = getObjByName("ReflectCreateObject");
/*demo->metaObject()返回与该类绑定的meta-object对象
QMetaObject::className()可以在运行时以字符串的形式返回类的名字
不需要C++编译器原生的运行时类型信息(RTTI)的支持。*/
qDebug() << demo->metaObject()->className();
/*通过名字动态设置和获取对象属性*/
auto readWrite = getObjByName("ReflectCreateObject");
readWrite->setProperty("name", "123");
qDebug() << readWrite->property("name").toString();
/*使用反射调用方法*/
auto reflectCallMethod = getObjByName("ReflectCreateObject");
QMetaObject::invokeMethod(reflectCallMethod, "func");
}
~ToolRegister() {}
private:
QObject* instance = NULL;
};
main.cpp
#include"ToolRegister.h"
#include <QtWidgets/QApplication>
#include <QScopedPointer>
#include <QPushButton>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
ToolRegister t;
t.show();
return a.exec();
}
输出:
ReflectCreateObject
"123"
hello world