利用Qt QMetaMethod 元数据实现调用安全调用对象的成员方法
参考链接:
https://doc.qt.io/qt-5/qmetamethod.html
https://blog.csdn.net/wangpengk7788/article/details/56291180
https://www.cnblogs.com/findumars/p/11161019.html
文章目录
1. 介绍 QMetaMethod
QMetaMethod 和 QMetaMethodPrivate 是用来管理QMetaObject包含信息中的函数节的。MOC生成的函数结构图如下
2. QMetaMethod方法介绍
// 这个枚举描述了一个方法的访问级别,遵循C++中使用的约定。
enum Access { Private, Protected, Public };
//
enum MethodType
{
Method, ///> 方法
Signal, ///> 信号
Slot, ///> 插槽
Constructor ///> 构造函数
};
// 方法的属性枚举类型
enum Attributes { Compatibility = 0x1, Cloned = 0x2, Scriptable = 0x4 };
// 返回此方法(private、protected或public)的访问规范。
QMetaMethod::Access access() const;
// 对对象调用对象使用此方法。如果可以调用成员,则返回true。如果没有这样的成员或参数不匹配,则返回false。
// 调用可以是同步调用,也可以是异步调用,具体取决于连接类型:
// Qt::DirectConnection 立即调用此方法
// Qt::QueuedConnection 应用程序进入主事件循环时将发布QEvent并调用该成员。
// Qt::AutoConnection 如果对象与调用方位于同一线程中,则会同步调用该成员;否则,它将异步调用该成员。
// 此方法调用的返回值放在returnValue中。如果调用是异步的,则无法计算返回值。最多可以向此方法调用传递十个参数\
// (val0、val1、val2、val3、val4、val5、val6、val7、val8和val9)。
// QGenericArgument和QGenericReturnArgument是内部帮助程序类。
// 因为可以动态调用信号和插槽,所以必须使用Q_ARG()和Q_RETURN_ARG()宏将参数括起来。Q_ARG()接受类型名和\
// 该类型的常量引用;Q_RETURN_ARG()接受类型名和非常量引用。
bool
invoke(QObject *object, // 对象句柄
Qt::ConnectionType connectionType,
QGenericReturnArgument returnValue,
QGenericArgument val0 = QGenericArgument(nullptr),
QGenericArgument val1 = QGenericArgument(),
QGenericArgument val2 = QGenericArgument(),
QGenericArgument val3 = QGenericArgument(),
QGenericArgument val4 = QGenericArgument(),
QGenericArgument val5 = QGenericArgument(),
QGenericArgument val6 = QGenericArgument(),
QGenericArgument val7 = QGenericArgument(),
QGenericArgument val8 = QGenericArgument(),
QGenericArgument val9 = QGenericArgument()) const;
// 在Q_GADGET上调用此方法。如果可以调用成员,则返回true。如果没有这样的成员或参数不匹配,则返回false。
// 调用总是同步的。
// Q_GADGET是Q_OBJECT宏的较轻版本,适用于不从QObject继承但仍希望使用QMetaObject提供的某些反射功能的类。它必须出现在类定义的私有部分。
bool
invokeOnGadget(void *gadget, // 指针小工具必须指向小工具类的实例。
QGenericReturnArgument returnValue,
QGenericArgument val0 = QGenericArgument(nullptr),
QGenericArgument val1 = QGenericArgument(),
QGenericArgument val2 = QGenericArgument(),
QGenericArgument val3 = QGenericArgument(),
QGenericArgument val4 = QGenericArgument(),
QGenericArgument val5 = QGenericArgument(),
QGenericArgument val6 = QGenericArgument(),
QGenericArgument val7 = QGenericArgument(),
QGenericArgument val8 = QGenericArgument(),
QGenericArgument val9 = QGenericArgument()) const;
// 如果此方法有效(可以内省和调用),则返回true,否则返回false。
bool QMetaMethod::isValid() const;
// 返回此方法的索引。
int QMetaMethod::methodIndex() const;
// 返回此方法的签名(例如,setValue(double))。
QByteArray QMetaMethod::methodSignature() const;
// 返回此方法的类型(信号、插槽或方法)。
QMetaMethod::MethodType QMetaMethod::methodType() const;
// 返回此方法的名称。
QByteArray QMetaMethod::name() const;
// 返回此方法的参数数。
int QMetaMethod::parameterCount() const;
// 返回参数名列表。
QList<QByteArray> QMetaMethod::parameterNames() const;
// 返回给定索引处参数的类型。
// 返回值是使用QMetaType注册的类型之一,如果未注册类型,则返回值为QMetaType::UnknownType。
int QMetaMethod::parameterType(int index) const;
// 返回参数类型的列表。
QList<QByteArray> QMetaMethod::parameterTypes() const;
// 返回此方法的返回类型。
// 返回值是使用QMetaType注册的类型之一,如果未注册类型,则返回值为QMetaType::UnknownType。
int QMetaMethod::returnType() const
// 如果方法修订版是由Q_revision指定的,则返回该方法修订版,否则返回0。
int QMetaMethod::revision() const;
// 返回此方法的返回类型名称。
const char *QMetaMethod::typeName() const;
// [static]
// 返回与给定信号对应的元方法,如果信号不是类的信号,则返回无效的QMetaMethod。
[static] QMetaMethod QMetaMethod::fromSignal(PointerToMemberFunction signal);
3. QMetaMethod使用方法
// header file.
// 我在这里创建的是Qt控制台程序。
// 习惯使用 C/C++ 标准输出方法,就没有使用 Qt 标注输出方法。
#pragma once
#if !defined(_QTOBJECT_H_)
#define _QTOBJECT_H_
#include <QObject>
class MyObject : public QObject
{
Q_OBJECT
public:
explicit MyObject(QObject* parent = 0){}
public slots:
int add(int a, int b) {
return 1;
}
void func()const{
printf("%s\n", __FUNCSIG__);
}
QString compute(QString str, int n, double f) {
printf(" %s : \n \t\t%s >> %d >> %.3f\n", __FUNCSIG__, str.toStdString().c_str(), n, f);
return __FUNCSIG__;
}
};
#endif // _QTOBJECT_H_
// main.cpp
MyObject obj;
QByteArray normalizedSignature = QMetaObject::normalizedSignature("add(int, int)");
int methodIndex = obj.metaObject()->indexOfMethod(normalizedSignature);
// 获取下标对应的元方法
//QMetaMethod metaMethod = obj.metaObject()->method(methodIndex);
// 返回与给定信号对应的元方法,如果信号不是类的信号,则返回无效的QMetaMethod。
QMetaMethod metaMethod = QMetaMethod::fromSignal(&QObject::destroyed);
// isValid
if (metaMethod.isValid()) {
qDebug() << QString::fromLocal8Bit("方法有效");
}
else {
qDebug() << QString::fromLocal8Bit("方法无效");
}
// function name string.
QString funcNameString;
funcNameString = metaMethod.typeName() + QString(" ") + metaMethod.name();
funcNameString += "(";
for (auto it = 0; it < metaMethod.parameterCount(); ++it) {
funcNameString += metaMethod.parameterTypes()[it] + QString(" ") + metaMethod.parameterNames()[it] + ",";
}
funcNameString += ");";
qDebug() << funcNameString;
// function access.
switch (metaMethod.access())
{
case QMetaMethod::Access::Private:
qDebug() << QString::fromLocal8Bit("访问级别: 私有访问级别.");
break;
case QMetaMethod::Access::Protected:
qDebug() << QString::fromLocal8Bit("访问级别: 保护访问级别.");
break;
case QMetaMethod::Access::Public:
qDebug() << QString::fromLocal8Bit("访问级别: 公有访问级别.");
break;
default:
qDebug() << QString::fromLocal8Bit("访问级别: 错误访问级别.");
break;
}
qDebug() << "Index: " << metaMethod.methodIndex();
qDebug() << "Signature: " << metaMethod.methodSignature();
qDebug() << "Type: " << metaMethod.methodType();
qDebug() << "Name: " << metaMethod.name();
qDebug() << "Parameter names: " << metaMethod.parameterNames();
qDebug() << "Return type: " << metaMethod.returnType();
qDebug() << "Type name: " << metaMethod.typeName();
int retVar =0;
if (metaMethod.invoke(&obj, Qt::AutoConnection, Q_RETURN_ARG(int, retVar), Q_ARG(int, 99), Q_ARG(int, -100)))
{
qDebug() << "call invoke sucess!";
}
else {
qDebug() << "call invoke faild.";
}
qDebug() << "call function return val: " << retVar;
输出信息
4. 总结
这个模块提供有关成员函数的元数据。能让我们灵活的,安全的调用对象方法,以及该方法的属性等接口。
作者:
怪小子
Github:
https://github.com/MrSunHua
邮箱:sh4a01@163.com
本文版权归作者和博客园共有,欢迎转载,如文章有版权冲突或者有更好的见解及建议,还望联系博主讨论并修改。