QMetaObjectPrivate 提供了对QMetaObject类成员中 uint类型数组的管理,这是个复杂的结构,因此QMetaObjectPrivate提供了结构的定义和操作函数,来方便对其的管理工作。
添加了 classInfo method emum property 后MOC生成的 QMetaObject.data 节
类的声明:
class Widget : public QWidget
{
Q_OBJECT
//Q_DECLARE_PRIVATE(Widget)
public:
Q_CLASSINFO("WidgetInfo", "InfoTest")
Q_PROPERTY(QString prop1 READ prop1)
enum SelectionBehavior {
SelectItems,
SelectRows,
SelectColumns
};
Q_ENUM(SelectionBehavior)
Q_FLAGS(SelectionBehavior)
Q_INVOKABLE void MethodTest(QString &,int);
public:
Widget(QWidget *parent = 0);
~Widget();
protected slots:
void TestSlot(QString &str);
signals:
void TestSignal1(QString &str);
void TestSignal2(QString &str,int i);
void TestSignal3();
};
对应的MOC生成的两个数组
static const qt_meta_stringdata_Widget_t qt_meta_stringdata_Widget = {
{
QT_MOC_LITERAL(0, 0, 6), // "Widget"
QT_MOC_LITERAL(1, 7, 10), // "WidgetInfo"
QT_MOC_LITERAL(2, 18, 8), // "InfoTest"
QT_MOC_LITERAL(3, 27, 11), // "TestSignal1"
QT_MOC_LITERAL(4, 39, 0), // ""
QT_MOC_LITERAL(5, 40, 8), // "QString&"
QT_MOC_LITERAL(6, 49, 3), // "str"
QT_MOC_LITERAL(7, 53, 11), // "TestSignal2"
QT_MOC_LITERAL(8, 65, 1), // "i"
QT_MOC_LITERAL(9, 67, 11), // "TestSignal3"
QT_MOC_LITERAL(10, 79, 8), // "TestSlot"
QT_MOC_LITERAL(11, 88, 10), // "MethodTest"
QT_MOC_LITERAL(12, 99, 5), // "prop1"
QT_MOC_LITERAL(13, 105, 17), // "SelectionBehavior"
QT_MOC_LITERAL(14, 123, 11), // "SelectItems"
QT_MOC_LITERAL(15, 135, 10), // "SelectRows"
QT_MOC_LITERAL(16, 146, 13) // "SelectColumns"
},
"Widget\0WidgetInfo\0InfoTest\0TestSignal1\0"
"\0QString&\0str\0TestSignal2\0i\0TestSignal3\0"
"TestSlot\0MethodTest\0prop1\0SelectionBehavior\0"
"SelectItems\0SelectRows\0SelectColumns"
};
#undef QT_MOC_LITERAL
static const uint qt_meta_data_Widget[] = {
// content:
7, // revision
0, // classname
1, 14, // classinfo
5, 16, // methods
1, 58, // properties
1, 61, // enums/sets
0, 0, // constructors
0, // flags
3, // signalCount
// classinfo: key, value
1, 2,
// signals: name, argc, parameters, tag, flags
3, 1, 41, 4, 0x06 /* Public */,
7, 2, 44, 4, 0x06 /* Public */,
9, 0, 49, 4, 0x06 /* Public */,
// slots: name, argc, parameters, tag, flags
10, 1, 50, 4, 0x09 /* Protected */,
// methods: name, argc, parameters, tag, flags
11, 2, 53, 4, 0x02 /* Public */,
// signals: parameters
QMetaType::Void, 0x80000000 | 5, 6,
QMetaType::Void, 0x80000000 | 5, QMetaType::Int, 6, 8,
QMetaType::Void,
// slots: parameters
QMetaType::Void, 0x80000000 | 5, 6,
// methods: parameters
QMetaType::Void, 0x80000000 | 5, QMetaType::Int, 4, 4,
// properties: name, type, flags
12, QMetaType::QString, 0x00095001,
// enums: name, flags, count, data
13, 0x1, 3, 65,
// enum data: key, value
14, uint(Widget::SelectItems),
15, uint(Widget::SelectRows),
16, uint(Widget::SelectColumns),
0 // eod
};
1, 14, // classinfo
5, 16, // methods
1, 58, // properties
1, 61, // enums/sets
前面是数量,后面是数据的相对偏移量。
QMetaObjectPrivate 类定义:
struct QMetaObjectPrivate
{
enum { OutputRevision = 7 }; // Used by moc, qmetaobjectbuilder and qdbus
int revision; 版本号
int className; 类名称索引
int classInfoCount, classInfoData; classInfo的数量,及索引 ,需要有宏定义才会被MOC生成
int methodCount, methodData; 函数数量及索引,需要有宏定义才会被MOC生成
int propertyCount, propertyData; property数量及索引,需要有宏定义才会被MOC生成
int enumeratorCount, enumeratorData; 枚举成员数量及索引,需要有宏定义才会被MOC生成
int constructorCount, constructorData; //since revision 2 构造函数数量及索引,需要有宏定义才会被MOC生成
int flags; //since revision 3 flags的数量
int signalCount; //since revision 4 信号数量
static inline const QMetaObjectPrivate *get(const QMetaObject *metaobject)
{ return reinterpret_cast<const QMetaObjectPrivate*>(metaobject->d.data); } 将QMetaObject的data指向的内存结构转为QMetaObjectPrivate的指针,来管理
static int originalClone(const QMetaObject *obj, int local_method_index);
static QByteArray decodeMethodSignature(const char *signature,
QArgumentTypeArray &types);
static int indexOfSignalRelative(const QMetaObject **baseObject,
const QByteArray &name, int argc,
const QArgumentType *types);
static int indexOfSlotRelative(const QMetaObject **m,
const QByteArray &name, int argc,
const QArgumentType *types);
static int indexOfSignal(const QMetaObject *m, const QByteArray &name,
int argc, const QArgumentType *types);
static int indexOfSlot(const QMetaObject *m, const QByteArray &name,
int argc, const QArgumentType *types);
static int indexOfMethod(const QMetaObject *m, const QByteArray &name,
int argc, const QArgumentType *types);
static int indexOfConstructor(const QMetaObject *m, const QByteArray &name,
int argc, const QArgumentType *types);
Q_CORE_EXPORT static QMetaMethod signal(const QMetaObject *m, int signal_index);
Q_CORE_EXPORT static int signalOffset(const QMetaObject *m);
Q_CORE_EXPORT static int absoluteSignalCount(const QMetaObject *m);
Q_CORE_EXPORT static int signalIndex(const QMetaMethod &m);
static bool checkConnectArgs(int signalArgc, const QArgumentType *signalTypes,
int methodArgc, const QArgumentType *methodTypes);
static bool checkConnectArgs(const QMetaMethodPrivate *signal,
const QMetaMethodPrivate *method);
static QList<QByteArray> parameterTypeNamesFromSignature(const char *signature);
#ifndef QT_NO_QOBJECT
//defined in qobject.cpp
enum DisconnectType { DisconnectAll, DisconnectOne };
static void memberIndexes(const QObject *obj, const QMetaMethod &member,
int *signalIndex, int *methodIndex);
static QObjectPrivate::Connection *connect(const QObject *sender, int signal_index,
const QMetaObject *smeta,
const QObject *receiver, int method_index_relative,
const QMetaObject *rmeta = 0,
int type = 0, int *types = 0);
static bool disconnect(const QObject *sender, int signal_index,
const QMetaObject *smeta,
const QObject *receiver, int method_index, void **slot,
DisconnectType = DisconnectAll);
static inline bool disconnectHelper(QObjectPrivate::Connection *c,
const QObject *receiver, int method_index, void **slot,
QMutex *senderMutex, DisconnectType = DisconnectAll);
#endif
};
1、 static int originalClone(const QMetaObject *obj, int local_method_index); 如果给出的 函数索引是克隆的返回原来的索引
int QMetaObjectPrivate::originalClone(const QMetaObject *mobj, int local_method_index)
{
Q_ASSERT(local_method_index < get(mobj)->methodCount);
int handle = get(mobj)->methodData + 5 * local_method_index; handle等于函数所在字段偏移量 每个函数段5个int大小
while (mobj->d.data[handle + 4] & MethodCloned) {
Q_ASSERT(local_method_index > 0);
handle -= 5;
local_method_index--; //往回遍历 找到flags为0x20的 为克隆的
}
return local_method_index;
}
2、QByteArray QMetaObjectPrivate::decodeMethodSignature(const char *signature,QArgumentTypeArray &types);
解析信号函数字符串, 将参数填充到QArgumentTypeArray 数组中, 并返回填充函数名称的QByteArray结构
QByteArray QMetaObjectPrivate::decodeMethodSignature(
const char *signature, QArgumentTypeArray &types)
{
Q_ASSERT(signature != 0);
const char *lparens = strchr(signature, '(');
if (!lparens)
return QByteArray();
const char *rparens = strrchr(lparens + 1, ')');
if (!rparens || *(rparens+1))
return QByteArray();
int nameLength = lparens - signature;
argumentTypesFromString(lparens + 1, rparens, types); 把函数参数()中的字符填充数组
return QByteArray::fromRawData(signature, nameLength); 将函数名块直接作为 QByteArray的数据返回。不做拷贝
}
这里引用到的结构 QArgumentType 标识某一函数参数的类
class QArgumentType
{
public:
QArgumentType(int type)
: _type(type)
{}
QArgumentType(const QByteArray &name)
: _type(qMetaTypeTypeInternal(name.constData())), _name(name)
{}
QArgumentType()
: _type(0)
{}
..............................
..............................略过
private:
int _type;
QByteArray _name;
};
argumentTypesFromString 解析以逗号分隔的参数列表,填充QArgumentTypes 并加到 QArgumentTypeArray数组中
// Parses a string of comma-separated types into QArgumentTypes.
// No normalization of the type names is performed.
static void argumentTypesFromString(const char *str, const char *end,
QArgumentTypeArray &types)
{
Q_ASSERT(str <= end);
while (str != end) {
if (!types.isEmpty())
++str; // Skip comma
const char *begin = str;
int level = 0;
while (str != end && (level > 0 || *str != ',')) {
if (*str == '<')
++level;
else if (*str == '>')
--level;
++str;
}
types += QArgumentType(QByteArray(begin, str - begin));
}
}
const QByteArray &name, int argc,
const QArgumentType *types);
返回信号相对于本类信号数组的索引值
int QMetaObjectPrivate::indexOfSignalRelative(const QMetaObject **baseObject,
const QByteArray &name, int argc,
const QArgumentType *types)
{
int i = indexOfMethodRelative<MethodSignal>(baseObject, name, argc, types); 调用全局模板函数indexOfMethodRelative来获取
#ifndef QT_NO_DEBUG
const QMetaObject *m = *baseObject;
if (i >= 0 && m && m->d.superdata) {
int conflict = indexOfMethod(m->d.superdata, name, argc, types);
if (conflict >= 0) {
QMetaMethod conflictMethod = m->d.superdata->method(conflict);
qWarning("QMetaObject::indexOfSignal: signal %s from %s redefined in %s",
conflictMethod.methodSignature().constData(),
objectClassName(m->d.superdata), objectClassName(m)); 如果父类定义了相同的信号 则输出警告
}
}
#endif
return i;
}
template<int MethodType>
static inline int indexOfMethodRelative(const QMetaObject **baseObject,
const QByteArray &name, int argc,
const QArgumentType *types)
{
for (const QMetaObject *m = *baseObject; m; m = m->d.superdata) {
Q_ASSERT(priv(m->d.data)->revision >= 7);
int i = (MethodType == MethodSignal)
? (priv(m->d.data)->signalCount - 1) : (priv(m->d.data)->methodCount - 1); //根据模板参数 MethodType 来决定返回那种函数的索引。信号还是
const int end = (MethodType == MethodSlot) 槽 还是成员函数
? (priv(m->d.data)->signalCount) : 0;
for (; i >= end; --i) {
int handle = priv(m->d.data)->methodData + 5*i;
if (methodMatch(m, handle, name, argc, types)) { methodMatch 对类名 函数名 函数参数 数量 进行匹配
*baseObject = m;
return i;
}
}
}
return -1;
}
priv(X) 是个内联函数 将QMetaObject::data 从uint* 转换为 QMetaObjectPrivate类型的指针
static inline Q_DECL_UNUSED const QMetaObjectPrivate *priv(const uint* data)
{ return reinterpret_cast<const QMetaObjectPrivate*>(data); }
4、indexOfSlotRelative 返回槽在其组中的索引
int QMetaObjectPrivate::indexOfSlotRelative(const QMetaObject **m,
const QByteArray &name, int argc,
const QArgumentType *types)
{
return indexOfMethodRelative<MethodSlot>(m, name, argc, types);
}
5、indexOfSignal indexOfSlot indexOfMethod 返回信号 槽 成员函数索引 这些索引是包括其祖父类在内的整个(继承和私有的共同组成)大数组里的索引
indexOfConstructor
int QMetaObjectPrivate::indexOfSignal(const QMetaObject *m, const QByteArray &name,
int argc, const QArgumentType *types)
{
int i = indexOfSignalRelative(&m, name, argc, types); 返回在自身数组中的索引
if (i >= 0)
i += m->methodOffset(); 返回继承的被放在祖父类staticMetaObject中的函数量
return i;
}
int QMetaObjectPrivate::indexOfSlot(const QMetaObject *m, const QByteArray &name,
int argc, const QArgumentType *types)
{
int i = indexOfSlotRelative(&m, name, argc, types);
if (i >= 0)
i += m->methodOffset();
return i;
}
int QMetaObjectPrivate::indexOfMethod(const QMetaObject *m, const QByteArray &name,
int argc, const QArgumentType *types)
{
int i = indexOfMethodRelative<0>(&m, name, argc, types);
if (i >= 0)
i += m->methodOffset();
return i;
}
int QMetaObjectPrivate::indexOfConstructor(const QMetaObject *m, const QByteArray &name,
int argc, const QArgumentType *types)
{
for (int i = priv(m->d.data)->constructorCount-1; i >= 0; --i) {
int handle = priv(m->d.data)->constructorData + 5*i;
if (methodMatch(m, handle, name, argc, types))
return i;
}
return -1;
}
6、QByteArray QMetaObjectPrivate::decodeMethodSignature 传递一个信号函数的字符串,将参数填充到QArgumentTypeArray中,将函数名填充QByteArray并返回
QByteArray QMetaObjectPrivate::decodeMethodSignature(
const char *signature, QArgumentTypeArray &types)
{
Q_ASSERT(signature != 0);
const char *lparens = strchr(signature, '(');
if (!lparens)
return QByteArray();
const char *rparens = strrchr(lparens + 1, ')');
if (!rparens || *(rparens+1))
return QByteArray();
int nameLength = lparens - signature;
argumentTypesFromString(lparens + 1, rparens, types);
return QByteArray::fromRawData(signature, nameLength);
}
7、QMetaMethod QMetaObjectPrivate::signal 传递信号的索引 返回标记了信号函数的QMetaMethod对象
QMetaMethod QMetaObjectPrivate::signal(const QMetaObject *m, int signal_index)
{
QMetaMethod result;
if (signal_index < 0)
return result;
Q_ASSERT(m != 0);
int i = signal_index;
i -= signalOffset(m);
if (i < 0 && m->d.superdata)
return signal(m->d.superdata, signal_index);
if (i >= 0 && i < priv(m->d.data)->signalCount) {
result.mobj = m;
result.handle = priv(m->d.data)->methodData + 5*i;
}
return result;
}
8、int QMetaObjectPrivate::absoluteSignalCount(const QMetaObject *m) 返回信号的个数 包括其基类的信号在内
int QMetaObjectPrivate::absoluteSignalCount(const QMetaObject *m)
{
Q_ASSERT(m != 0);
int n = priv(m->d.data)->signalCount;
for (m = m->d.superdata; m; m = m->d.superdata)
n += priv(m->d.data)->signalCount;
return n;
}
9、bool QMetaObjectPrivate::checkConnectArgs(int signalArgc, const QArgumentType *signalTypes,
int methodArgc, const QArgumentType *methodTypes)
bool QMetaObjectPrivate::checkConnectArgs(const QMetaMethodPrivate *signal,
const QMetaMethodPrivate *method)
检测信号和要链接的函数 参数是否匹配