1 反射机制
C#中支持反射机制而C++中不支持,基于QT的元对象系统,之前使用QT的反射机制创建属性表,现学习使用QT通过类名动态创建对象。
new和反射创建对象区别:
new用于创建编译期就确定类型的对象, 反射在运行时才确定要创建的类型并创建对象.
反射机制的优点:
- 1、反射提高了程序的灵活性和扩展性。
- 2、降低耦合性,提高自适应能力。
- 3、它允许程序创建和控制任何类的对象,无需提前硬编码目标类。
2 结果现象
输入MyClass类名,可以动态创建对象,访问类中的属性方法。
3 程序代码
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QByteArray>
#include <QMetaObject>
#include <QHash>
#include <QLineEdit>
#include <QMetaProperty>
#include <QPushButton>
#include <QDebug>
#pragma execution_character_set("utf-8")
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MyClass;
class MyClass : public QWidget
{
Q_OBJECT
public:
MyClass(QWidget *parent = nullptr);
Q_PROPERTY(uint uCrc READ uCrc WRITE setuCrc)
Q_PROPERTY(uint StructLen READ StructLen WRITE setStructLen)
~MyClass();
int num;
void pCout();
uint uCrc() const
{
qDebug()<<"uCrc"<<m_uCrc;
return m_uCrc;
}
uint StructLen() const
{
return m_StructLen;
}
public slots:
void setuCrc(uint uCrc)
{
qDebug()<<"setuCrc"<<uCrc<<"success!!!!!!!!!!!!!!!";
m_uCrc = uCrc;
}
void setStructLen(uint StructLen)
{
m_StructLen = StructLen;
}
private:
uint m_uCrc;
uint m_StructLen;
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
QStringList m_Register;
void create(QString name);
private slots:
void on_lineEdit_editingFinished();
private:
Ui::MainWindow *ui;
};
#ifndef REFLECT_H
#define REFLECT_H
template<typename L>
class Reflect
{
public:
template<typename T>
static void registerClass(QString name)
{
constructors().insert( name.toLatin1(), &constructorHelper<T> );
}
static QObject* newInstance( const QByteArray& className, L* parent = nullptr )
{
Constructor constructor = constructors().value( className );
if ( constructor == nullptr )
return nullptr;
return (*constructor)( parent );
}
private:
typedef QObject* (*Constructor)( L* parent );
template<typename T>
static QObject* constructorHelper( L* parent )
{
return new T( parent );
}
static QHash<QByteArray, Constructor>& constructors()
{
static QHash<QByteArray, Constructor> instance;
return instance;
}
};
#endif // REFLECT_H
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
Reflect<QWidget>::registerClass<QLineEdit>("QLineEdit");
Reflect<QWidget>::registerClass<QPushButton>("QPushButton");
Reflect<QWidget>::registerClass<MyClass>("MyClass");
m_Register.append("QLineEdit");
m_Register.append("QPushButton");
m_Register.append("MyClass");
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::create(QString name)
{
qDebug()<<"start";
QObject *object = Reflect<QWidget>::newInstance(name.toUtf8());
const QMetaObject *p = object->metaObject();
//打印属性与方法名
for(int i = 0;i < p->methodCount();i++)
{
qDebug()<<p->method(i).name()<<"~~~~~~method~~~~~~";
}
for(int i = 0;i < p->propertyCount();i++)
{
qDebug()<<p->property(i).name()<<"----property---";
}
/**
* @brief 动态创建名称为 name 的类
* 该程序测试的类名 name = MyClass
* 之后进行测试打印 MyClass类 中的uCrc
* 成功打印setuCrc 12 success!!!!!!!!!!!!!!!
*
*/
qDebug()<<"===============================";
QMetaProperty pe = p->property(p->indexOfProperty("uCrc"));
pe.write(object,12);
qDebug()<<"end";
}
MyClass::MyClass(QWidget *parent)
{
parent = nullptr;
}
MyClass::~MyClass()
{
delete this;
}
void MyClass::pCout()
{
qDebug()<<"pCout";
}
void MainWindow::on_lineEdit_editingFinished()
{
QString str = ui->lineEdit->text();
if(!m_Register.contains(str))
return ;
this->create(str);
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}