qt creator 4.8.0   /qt version 5.12.0
有人将qt的meta系统称为“元对象系统”、“元系统”,“MetaObject系统”,我这里统称为meta系统。meta系统除了包含MetaObject类及其还有很多独特的数据结构和方法,并且强烈依赖moc生成meta系统所必须的一些代码和数据。所以我称之为meta系统。

希望让继承自QObject类的meta系统中拥有constructor相关信息,能让QMetaObject通过NewInstance生成类对象,需要在构造函数前加Q_INVOKABLE宏。这样类的构造函数才能进入MetaObect系统。

//base.h
class Base : public QObject
{Q_OBJECTQ_CLASSINFO("name","fund")
public:enum XType{AA,BB,CC};Q_ENUM(XType);
//Q_INVOKABLE宏让构造函数进入meta系统中Q_INVOKABLE explicit Base(QObject *parent = nullptr); Q_INVOKABLE Base(int a,int b,QObject *parent = nullptr);Q_INVOKABLE Base(int a,QObject *parent = nullptr);Q_INVOKABLE void fun();void funt();signals:void sig(float c,char d);void sig1();void sig2();public slots:void fun1(float a,char b);void fun2();private:QTimer t;int a;
};
};--------------------------------------------------
//moc_base.cpp
static const qt_meta_stringdata_Base_t qt_meta_stringdata_Base = {{
QT_MOC_LITERAL(0, 0, 4), // "Base"
QT_MOC_LITERAL(1, 5, 4), // "name"
QT_MOC_LITERAL(2, 10, 4), // "fund"
QT_MOC_LITERAL(3, 15, 3), // "sig"
QT_MOC_LITERAL(4, 19, 0), // ""
QT_MOC_LITERAL(5, 20, 1), // "c"
QT_MOC_LITERAL(6, 22, 1), // "d"
QT_MOC_LITERAL(7, 24, 4), // "sig1"
QT_MOC_LITERAL(8, 29, 4), // "sig2"
QT_MOC_LITERAL(9, 34, 4), // "fun1"
QT_MOC_LITERAL(10, 39, 1), // "a"
QT_MOC_LITERAL(11, 41, 1), // "b"
QT_MOC_LITERAL(12, 43, 4), // "fun2"
QT_MOC_LITERAL(13, 48, 3), // "fun"  //Q_INVOKABLE将普通函数纳入到了meta系统中
QT_MOC_LITERAL(14, 52, 6), // "parent"
QT_MOC_LITERAL(15, 59, 5), // "XType"
QT_MOC_LITERAL(16, 65, 2), // "AA"
QT_MOC_LITERAL(17, 68, 2), // "BB"
QT_MOC_LITERAL(18, 71, 2) // "CC"},"Base\0name\0fund\0sig\0\0c\0d\0sig1\0sig2\0""fun1\0a\0b\0fun2\0fun\0parent\0XType\0AA\0BB\0""CC"
};
#undef QT_MOC_LITERALstatic const uint qt_meta_data_Base[] = {// content:8,       // revision0,       // classname1,   14, // classinfo6,   16, // methods  //methodcount  methoddata(qt_meta_data_Base[16])0,    0, // properties1,   84, // enums/sets //enumcount  enumdata
//注意这里的constructors数量是6。带默认参数的构造函数被拆分成带该参数和不带该参数两个函数去了。6,   95, // constructors 0,       // flags3,       // signalCount
//下面数组中key,value项表示在qt_meta_stringdata_Base中该函数名字的下标// classinfo: key, value1,    2,
//下面数组中name项表示在qt_meta_stringdata_Base中该函数名字的下标,argc表示参数个数,
//parameters表示该函数参数的起始描述在qt_meta_data_Base中的下标,
//tag描述tag在qt_meta_stringdata_Base中该tag的名字下标,flags为qmetaobject_p.h中
//enum MethodFlags类型数据的组合// signals: name, argc, parameters, tag, flags3,    2,   46,    4, 0x06 /* Public */,7,    0,   51,    4, 0x06 /* Public */,8,    0,   52,    4, 0x06 /* Public */,// slots: name, argc, parameters, tag, flags9,    2,   53,    4, 0x0a /* Public */,12,    0,   58,    4, 0x0a /* Public */,//类中被Q_INVOCABLE的普通函数在qt_meta_data_Base中的存放记录
// methods: name, argc, parameters, tag, flags  13,    0,   59,    4, 0x02 /* Public */,
//5,6 分别表示参数名字在qt_meta_stringdata_Base中的下标// signals: parametersQMetaType::Void, QMetaType::Float, QMetaType::Char,    5,    6,QMetaType::Void,QMetaType::Void,// slots: parametersQMetaType::Void, QMetaType::Float, QMetaType::Char,   10,   11,QMetaType::Void,// methods: parametersQMetaType::Void,//构造函数被Q_INVOKABLE修饰后在qt_meta_data_Base中的存放记录 // constructors: parameters   0x80000000 | 4, QMetaType::QObjectStar,   14, //带 有默认参数值的构造函数0x80000000 | 4,   //不带 有默认参数值的构造函数0x80000000 | 4, QMetaType::Int, QMetaType::Int, QMetaType::QObjectStar,   10,   11,   14,0x80000000 | 4, QMetaType::Int, QMetaType::Int,   10,   11,0x80000000 | 4, QMetaType::Int, QMetaType::QObjectStar,   10,   14,0x80000000 | 4, QMetaType::Int,   10,// enums: name, alias, flags, count, data15,   15, 0x0,    3,   89,// enum data: key, value16, uint(Base::AA),17, uint(Base::BB),18, uint(Base::CC),// constructors: name, argc, parameters, tag, flags0,    1,   60,    4, 0x0e /* Public */,0,    0,   63,    4, 0x2e /* Public | MethodCloned */,0,    3,   64,    4, 0x0e /* Public */,0,    2,   71,    4, 0x2e /* Public | MethodCloned */,0,    2,   76,    4, 0x0e /* Public */,0,    1,   81,    4, 0x2e /* Public | MethodCloned */,0        // eod
};--------------------------------------------------int main()
{Base ba;QMetaObject qme= ba.staticMetaObject;int count = qme.methodCount();for(int i=0;i<count;i++){QMetaMethod me = qme.method(i);qDebug()<<me.name()<<endl;}
}
/*输出:
"destroyed""destroyed""objectNameChanged""deleteLater""_q_reregisterTimers"
//前面5个是QObject中的method,method包括qt_meta_data_Base中的signals,slots,methods"sig""sig1""sig2""fun1""fun2""fun"
*/

Q_INVOKABLE的作用还可以将普通函数也纳入meta系统中。这样可以通过QMetaObject 的invokemethod方法来调用对应函数。这种方式可以让代码系统变得轻类型的,主要应用于RPC的时候。

QMetaObjectPrivate定义在Src\qtbase\src\corelib\kernel\qmetaobject_p.h  中,QMetaObject实现过程中对QMetaObjectPrivate的依赖非常隐秘。QMetaObject没有显示的声明QMetaObjectPrivate相关的数据成员,而是在使用时隐秘的将QMetaObject的数据成员d->data转成QMetaObjectPrivate对象后直接使用。举例如下。

//moc_base.cpp中meta_data的定义
static const uint qt_meta_data_Base[] = {// content:8,       // revision0,       // classname1,   14, // classinfo6,   16, // methods1,   84, // properties1,   87, // enums/sets6,   98, // constructors0,       // flags3,       // signalCount// classinfo: key, value1,    2,// signals: name, argc, parameters, tag, flags3,    2,   46,    4, 0x06 /* Public */,7,    0,   51,    4, 0x06 /* Public */,8,    0,   52,    4, 0x06 /* Public */,// slots: name, argc, parameters, tag, flags9,    2,   53,    4, 0x0a /* Public */,12,    0,   58,    4, 0x0a /* Public */,// methods: name, argc, parameters, tag, flags13,    0,   59,    4, 0x02 /* Public */,
.....
}//对staticMetaObject 对象的数据成员d赋值。
QT_INIT_METAOBJECT const QMetaObject Base::staticMetaObject = { {&B::staticMetaObject,qt_meta_stringdata_Base.data,qt_meta_data_Base,  //meta_data赋予给staticmetaObject对象成员d->dataqt_static_metacall,nullptr,nullptr
} };--------------------------------------------------
//qmetaobject_p.h中定义QMetaObjectPrivate类
struct QMetaObjectPrivate
{// revision 7 is Qt 5.0 everything lower is not supported// revision 8 is Qt 5.12: It adds the enum name to QMetaEnumenum { OutputRevision = 8 }; // Used by moc, qmetaobjectbuilder and qdbusint revision; int className;int classInfoCount, classInfoData;int methodCount, methodData;int propertyCount, propertyData;int enumeratorCount, enumeratorData;int constructorCount, constructorData;int flags;int signalCount;
//sizeof(QMetaObjectPrivate)等于从revision到signalCount一共14个数据成员大小
........}
--------------------------------------------------
//qobjectdefs.h中定义QMetaObject类
struct Q_CORE_EXPORT QMetaObject
{
......struct { // private dataconst QMetaObject *superdata;const QByteArrayData *stringdata;const uint *data;typedef void (*StaticMetacallFunction)(QObject *, QMetaObject::Call, int, void **);StaticMetacallFunction static_metacall;const QMetaObject * const *relatedMetaObjects;void *extradata; //reserved for future use} d;  //QMetaObject的数据成员d,也是唯一的数据成员。sizeof(QMetaObject) == sizeof(d)
}--------------------------------------------------//qmetaobject.cpp
static inline const QMetaObjectPrivate *priv(const uint* data)
{ return reinterpret_cast<const QMetaObjectPrivate*>(data); }//qmetaObject与QmetaObjectPrivate没有直接的显示的关联,其关联用法如下。
int QMetaObject::methodOffset() const
{int offset = 0;const QMetaObject *m = d.superdata;while (m) {
//通过priv函数将uint*data强制转换成QmetaObjectPrivate对象,并获取到对象的数据成员。offset += priv(m->d.data)->methodCount;  m = m->d.superdata;}return offset;
}/*
......// signals: name, argc, parameters, tag, flags3,    2,   46,    4, 0x06 /* Public */,7,    0,   51,    4, 0x06 /* Public */,8,    0,   52,    4, 0x06 /* Public */,// slots: name, argc, parameters, tag, flags9,    2,   53,    4, 0x0a /* Public */,12,    0,   58,    4, 0x0a /* Public */,// methods: name, argc, parameters, tag, flags13,    0,   59,    4, 0x02 /* Public */,
......
*/
//从qt_meta_data_Base中获取函数参数个数。本质就是获取signals/slots/methods的argc项
int QMetaMethodPrivate::parameterCount() const
{Q_ASSERT(priv(mobj->d.data)->revision >= 7);return mobj->d.data[handle + 1];
}

可以确认,QPrivateMetaObject对象强制转换实例化只使用了qt_meta_data_Base的content部分,qt_meta_data_Base后面的数据(content之后的数据)都是根据QPrivateMetaObject、QMetaMethod、QMetaMethodPrivate、QMetaObject中的方法进行解析。
QmetaMethodPrivate定义在qmetaobject.cpp中。

qt meta系统中为每一个标记为meta系统的函数都预留了一个tag项,这里的tag(标记)是一个极为宽泛的概念,他包含了C++关键字、C++属性修饰词、自定义类名等等,tag项默认值为“”(空字符串),正常也应该为“”(空字符串),但是当qt遇到C++中合法而moc的语法器无法识别(可能qt开发者忘记写了)的symbol(具有特殊意义的字符串)时,就将该symbol当做一个tag(标记)。比如为slot或signal或Q_INVOKABLE标记的函数 添加__stdcall 或__cdecl (函数调用规范) 属性 修饰时,就会出现将__stdcall 或__cdecl标记 当做未识别的tag的情况,虽然最后程序会报错。

//A.h
class A{Q_OBJECT
public:B(QObject *parent = nullptr);
signals :void sig();void __stdcall sig1();//(int a);  //构建生成moc_A.cpp后会报错
};
-----------------------------
//moc_A.cpp
static const qt_meta_stringdata_A_t qt_meta_stringdata_A = {{
QT_MOC_LITERAL(0, 0, 1), // "A"
QT_MOC_LITERAL(1, 2, 3), // "sig"
QT_MOC_LITERAL(2, 6, 0), // ""
QT_MOC_LITERAL(3, 7, 4), // "sig1"
QT_MOC_LITERAL(4, 12, 9), // "__stdcall"  //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
QT_MOC_LITERAL(5, 22, 4) // "void"},"A\0sig\0\0sig1\0__stdcall\0void"
};static const uint qt_meta_data_A[] = {// content:8,       // revision0,       // classname0,    0, // classinfo1,   14, // methods0,    0, // properties0,    0, // enums/sets0,    0, // constructors0,       // flags1,       // signalCount// signals: name, argc, parameters, tag, flags1,    0,   24,    2, 0x06 /* Public */,3,    0,   25,    5, 0x06 /* Public */,// signals: parameters0x80000000 | 2,0        // eod
};void A::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{if (_c == QMetaObject::InvokeMetaMethod) {A *_t = static_cast<A *>(_o);Q_UNUSED(_t)switch (_id) {case 0: _t->sig(); break;case 1: { __stdcall _r = _t->sig1();  //errorif (_a[0]) *reinterpret_cast< __stdcall*>(_a[0]) = std::move(_r); }  break;default: ;}} else if (_c == QMetaObject::IndexOfMethod) {int *result = reinterpret_cast<int *>(_a[0]);{using _t = void (A::*)();if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&A::sig)) {*result = 0;return;}}{using _t = __stdcall (A::*)();  //errorif (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&A::sig1)) {*result = 1;return;}}}
}

利用利用 Q_INVOKABLE 和 QMetaObject::newInstance来生成对象的新实例_hanhanluma的博客-CSDN博客meta programing思想:元编程 (meta-programming) - 知乎 
CC++中tag和type - 百度文库

QMetaObjectPrivate meta_constractors Q_INVOKABLE相关推荐

  1. 6. Qt 信号与信号槽(4)-QMetaObjectPrivate

    QMetaObjectPrivate是QMetaObjectd指针里面的data成员 struct QMetaObjectPrivate {// revision 7 is Qt 5.0 everyt ...

  2. Qt文档阅读笔记-Q_INVOKABLE官方解析及Qt中反射的使用

    Q_INVOKABLE宏定义了函数在元对象中可以进行调用,这个宏要写到返回值的前面,也就是函数的开头,如下例子: class Window : public QWidget{Q_OBJECTpubli ...

  3. Q_INVOKABLE与invokeMethod用法详解

    Q_INVOKABLE与invokeMethod用法全解 请尊重原创作品和译文.转载请保持文章完整性,并以超链接形式注明原始作者地址http://blog.csdn.net/changsheng230 ...

  4. QML < 5 > QML 访问C++ 类 (函数Q_INVOKABLE、枚举Q_ENUMS 、成员变量Q_PROPERTY、自定义结构体QVariantMap、List数据QVariantL

    QML < 5 > QML 访问C++ 类 (函数Q_INVOKABLE.枚举Q_ENUMS .成员变量Q_PROPERTY.自定义结构体(QVariantMap ).List数据QVar ...

  5. Qt ASSERT:QMetaObjectPrivate::get(smeta)-revision= 7in file kernel\qobject.cpp,line 2646

    qt5.6.1所做的工程在运行时出现该问题:该问题说的是信号槽中 函数的参数不匹配. 在qt4.8.4 中QThread 中查到assitant中定义void QThread::finished () ...

  6. Qt / Moc 和信号 - 槽解析

    目录 一. MOC 二. moc_test.cpp 分析 三. connect 四. activate 五. 总结 版本 Qt5.12.3 moc_test.cpp 位于可执行文件目录下,其余源代码都 ...

  7. 6、Qt Meta Object system 学习

    原文地址:http://blog.csdn.net/ilvu999/article/details/8049908 使用 meta object system 继承自 QOject 类定义中添加 Q_ ...

  8. qt源码学习---QMetaObject(二)

    1.由于QMetaObject依赖于QMetaMethod.QMetaEnum.QMetaProperty.QMetaClassInfo等类,本篇先看下QMetaMethod方法的实现: 2.QMet ...

  9. 基于Qt5.14.2和mingw的Qt源码学习(三) — 元对象系统简介及moc工具是如何保存类属性和方法的

    基于Qt5.14.2和mingw的Qt源码学习(三) - 元对象系统简介及moc工具是如何保存类属性和方法的 一.什么是元对象系统 1.元对象系统目的 2.实现元对象系统的关键 3.元对象系统的其他一 ...

最新文章

  1. PHP基础封装简单的MysqliHelper类
  2. Oracle感慨(转)
  3. tomcat常见面试题目问答Top10
  4. matlab实时数据传输,利用QuaRC实现c++与simulink(matlab)之间实时双向数据传输
  5. 使用ExecutorService来停止线程服务
  6. 洛谷P3381 【模板】最小费用最大流
  7. docker nginx:1.21.4
  8. VxWorks程序一下载就停住了
  9. [YARN-1963] 支持同一个队列内作业按优先级调度
  10. Centos6.5之yum安装LAMP+wordpress
  11. nvinfer1::cudnn::Engine::deserialize()出错的原因
  12. 小米3g刷高格固件_小米路由器3G版padavan老毛子原版固件
  13. 用c语言编写清理c盘程序,C盘清理小程序制作
  14. 4.3-软件开发中,“原型图”的作用与绘制方法说明
  15. win2008服务器系统玩红警,win8系统玩不了红色警戒2如何解决?win8系统玩不了红色警戒2解决方法...
  16. python常用的颜色英文表达_面料颜色中英文翻译对照表
  17. 直方图python_Python数据可视化的例子——直方图和核密度曲线
  18. word与mathtype——“运行时错误48,文件未找到:MathPage.wll”解决
  19. centos 挂载 cos云存储服务器,centos文件目录挂载docker实现共享操作步骤
  20. 启动类上的@MapperScan注解与yml配置中mybatis.mapper-locations和mybatis.type-aliases-package的作用

热门文章

  1. 程序员如何在技术上提升自己
  2. nc文件在ncl中取代nan值为缺省值
  3. html页面执行sql语句,关于在页面上执行sql语句
  4. Protractor 怎么编写自动化测试用例
  5. Go-directed and habitual learning
  6. 在vue项目中使用favicon.ico
  7. 几种矩阵分解算法: LU分解,Cholesky分解,QR分解,SVD分解,Jordan分解
  8. redis下载(windows版)
  9. 多目标粒子群算法求解帕累托前沿Pareto,Pareto的原理,测试函数100种求解之21
  10. java request reponse 乱码的问题解决