Created
March 15, 2016 01:09
-
-
Save 0xlitf/9f4fef897f18c38a9670 to your computer and use it in GitHub Desktop.
Q_DECLARE_METATYPE与qRegisterMetaType学习
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 基本理解 | |
| Q_DECLARE_METATYPE | |
| 如果要使自定义类型或其他非QMetaType内置类型在QVaiant中使用,必须使用该宏。 | |
| 该类型必须有公有的 构造、析构、复制构造 函数 | |
| qRegisterMetaType 必须使用该函数的两种情况 | |
| 如果非QMetaType内置类型要在 Qt 的属性系统中使用 | |
| 如果非QMetaType内置类型要在 queued 信号与槽 中使用 | |
| 二者关系 | |
| 二者的代码: | |
| Q_DECLARE_METATYPE 展开后是一个特化后的类 QMetaTypeId<TYPE> | |
| qRegisterMetaType 将某类型注册中 MetaType 系统中 | |
| 二者的联系: | |
| QMetaTypeId<TYPE>的类中的成员包含对qRegisterMetaType的调用 | |
| 我们知道类中的成员函数并不一定会被调用(即,该宏并不确保类型被注册到MetaType)。 | |
| 通过qRegisterMetaType可以确保类型被注册 | |
| 两个qRegisterMetaType 的联系 | |
| 无参的qRegisterMetaType函数会通过该成员调用带参数的qRegisterMetaType() | |
| 这两个东西真难理清,不妨看看源码吧。 | |
| Q_DECLARE_METATYPE | |
| 代码来源:src/corelib/kernel/qmetatype.h | |
| #define Q_DECLARE_METATYPE(TYPE) \ | |
| QT_BEGIN_NAMESPACE \ | |
| template <> \ | |
| struct QMetaTypeId< TYPE > \ | |
| { \ | |
| enum { Defined = 1 }; \ | |
| static int qt_metatype_id() \ | |
| { \ | |
| static QBasicAtomicInt metatype_id = Q_BASIC_ATOMIC_INITIALIZER(0); \ | |
| if (!metatype_id) \ | |
| metatype_id = qRegisterMetaType< TYPE >(#TYPE); \ | |
| return metatype_id; \ | |
| } \ | |
| }; \ | |
| QT_END_NAMESPACE | |
| 宏展开是一个在Qt的命名空间中的一个类模板的特化 QMetaTypeId<TYPE> | |
| 该类含一个enum和一个返回!QMetaType的id的成员函数 | |
| qRegisterMetaType(const char *typeName) | |
| 代码来源:src/corelib/kernel/qmetatype.h | |
| template <typename T> | |
| int qRegisterMetaType(const char *typeName) | |
| { | |
| typedef void*(*ConstructPtr)(const T*); | |
| ConstructPtr cptr = qMetaTypeConstructHelper<T>; | |
| typedef void(*DeletePtr)(T*); | |
| DeletePtr dptr = qMetaTypeDeleteHelper<T>; | |
| return QMetaType::registerType(typeName, reinterpret_cast<QMetaType::Destructor>(dptr), | |
| reinterpret_cast<QMetaType::Constructor>(cptr)); | |
| } | |
| 该函数的核心就是调用了registerType 函数 | |
| 两个Helper模板函数分别对构造和析构函数进行封装 | |
| registerType | |
| 代码来源:src/corelib/kernel/qmetatype.cpp | |
| int QMetaType::registerType(const char *typeName, Destructor destructor, Constructor constructor) | |
| 函数功能: | |
| 根据类型名查找其MetaType类型,如果已存在,则直接返回;否则创建后返回。 | |
| 创建一个 !QCustomTypeInfo 对象 | |
| 该对象包含要类型的构造、析构信息,已经规范化后的类型名 | |
| 该对象存入一个全局的!QVector中 | |
| qRegisterMetaType() | |
| 看manual,可以知道,qRegisterMetaType 还有一个无参的重载函数。 | |
| template <typename T> | |
| inline int qRegisterMetaType() | |
| { | |
| return qMetaTypeId(static_cast<T *>(0)); | |
| } | |
| 函数看起来和带参数的那个似乎区别很大(难道不是么?)。 | |
| 手册中告诉我们,执行这个的时候,模板参数T必须用 Q_DECLARE_METATYPE() 声明过 | |
| 能猜到原因吗?注意看前面 Q_DECLARE_METATYPE() 代码, | |
| 对了。类中的成员函数qt_metatype_id中包含对qRegisterMetaType(typeName)的调用 | |
| 这儿就是辗转调用了这个带参数的qRegisterMetaType函数 | |
| unregisterType(const char *typeName) | |
| 函数的作用是取消自己先前注册的某个metatype类型。 | |
| 前面提到注册信息在一个全局的 QVector<QCustomTypeInfo>中,当取消注册的时候是怎么样的呢?直接删除Vector中相应的项么?源码告诉我们,不是的。 | |
| 实际是查找到相应的项,清空该项的内容。 | |
| for (int v = 0; v < ct->count(); ++v) | |
| { | |
| if (ct->at(v).typeName == typeName) | |
| { | |
| QCustomTypeInfo &inf = (*ct)[v]; | |
| inf.typeName.clear(); | |
| inf.constr = 0; | |
| inf.destr = 0; | |
| inf.alias = -1; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment