QMetaMethod 和 QMetaMethodPrivate 是用来管理QMetaObject包含信息中的函数节的。MOC生成的函数结构图如下
首先是字符串结构
函数结构图:
每个函数节 占5个int ,第一个是函数名字符串,在字符串数组中的索引值为3,刚好对应字符数组中的“TestSignal3”,第三个是其参数段的偏移量41刚好是,第一个参数节
参数节的构成图:
QMetaMethod 和 QMetaMethodPrivate 的定义
class Q_CORE_EXPORT QMetaMethod
{
public:
Q_DECL_CONSTEXPR inline QMetaMethod() : mobj(Q_NULLPTR), handle(0) {}
QByteArray methodSignature() const;
QByteArray name() const;
const char *typeName() const;
int returnType() const;
int parameterCount() const;
int parameterType(int index) const;
void getParameterTypes(int *types) const;
QList<QByteArray> parameterTypes() const;
QList<QByteArray> parameterNames() const;
const char *tag() const;
enum Access { Private, Protected, Public };
Access access() const;
enum MethodType { Method, Signal, Slot, Constructor };
MethodType methodType() const;
enum Attributes { Compatibility = 0x1, Cloned = 0x2, Scriptable = 0x4 };
int attributes() const;
int methodIndex() const;
int revision() const;
inline const QMetaObject *enclosingMetaObject() const { return mobj; }
............................................................省略
inline bool isValid() const { return mobj != Q_NULLPTR; }
#ifdef Q_QDOC
static QMetaMethod fromSignal(PointerToMemberFunction signal);
#else
template <typename Func>
static inline QMetaMethod fromSignal(Func signal)
{
typedef QtPrivate::FunctionPointer<Func> SignalType;
Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
"No Q_OBJECT in the class with the signal");
return fromSignalImpl(&SignalType::Object::staticMetaObject,
reinterpret_cast<void **>(&signal));
}
#endif
private:
static QMetaMethod fromSignalImpl(const QMetaObject *, void **);
const QMetaObject *mobj;
uint handle;
friend class QMetaMethodPrivate;
friend struct QMetaObject;
friend struct QMetaObjectPrivate;
friend class QObject;
friend bool operator==(const QMetaMethod &m1, const QMetaMethod &m2);
friend bool operator!=(const QMetaMethod &m1, const QMetaMethod &m2);
};
class QMetaMethodPrivate : public QMetaMethod
{
public:
static const QMetaMethodPrivate *get(const QMetaMethod *q)
{ return static_cast<const QMetaMethodPrivate *>(q); }
inline QByteArray signature() const;
inline QByteArray name() const;
inline int typesDataIndex() const;
inline const char *rawReturnTypeName() const;
inline int returnType() const;
inline int parameterCount() const;
inline int parametersDataIndex() const;
inline uint parameterTypeInfo(int index) const;
inline int parameterType(int index) const;
inline void getParameterTypes(int *types) const;
inline QList<QByteArray> parameterTypes() const;
inline QList<QByteArray> parameterNames() const;
inline QByteArray tag() const;
inline int ownMethodIndex() const;
private:
QMetaMethodPrivate();
}
两个数据成员 mobj QMetaObject类的指针, handle 函数节的偏移量, 所有的方法都围绕这两个成员展开。
QMetaMethodPrivate 的构造函数是私有的 只能通过 static const QMetaMethodPrivate *get(const QMetaMethod *q) 静态函数 将QMetaMethod 对象指针转换为
QMetaMethodPrivate指针来使用该类的函数
1、QByteArray QMetaMethodPrivate::name() ; 返回 QByteArray标识了函数的名称
QByteArray QMetaMethodPrivate::name() const
{
Q_ASSERT(priv(mobj->d.data)->revision >= 7);
return stringData(mobj, mobj->d.data[handle]); 传函数节的第一个int给Index
}
static inline const QByteArray stringData(const QMetaObject *mo, int index)
{
Q_ASSERT(priv(mo->d.data)->revision >= 7); 版本检查
const QByteArrayDataPtr data = { const_cast<QByteArrayData*>(&mo->d.stringdata[index]) }; 节的第一个int值为函数名在stringdata中的索引
Q_ASSERT(data.ptr->ref.isStatic());
Q_ASSERT(data.ptr->alloc == 0);
Q_ASSERT(data.ptr->capacityReserved == 0);
Q_ASSERT(data.ptr->size >= 0);
return data; 这里用节数据直接构成QbyteArray对象,不做深拷贝,
}
2、int QMetaMethodPrivate:: parameterCount () 返回函数的参数个数
int QMetaMethodPrivate::parameterCount() const
{
Q_ASSERT(priv(mobj->d.data)->revision >= 7);
return mobj->d.data[handle + 1]; 函数节的第二个int标识了参数个数
}
3、int QMetaMethodPrivate::typesDataIndex() const 返回参数节的偏移量
int QMetaMethodPrivate::typesDataIndex() const
{
Q_ASSERT(priv(mobj->d.data)->revision >= 7);
return mobj->d.data[handle + 2]; 函数节的第三个int标识了参数节的偏移量
}
4、int QMetaMethodPrivate::parametersDataIndex() const 返回参数节中 参数块的偏移
int QMetaMethodPrivate::parametersDataIndex() const
{
Q_ASSERT(priv(mobj->d.data)->revision >= 7);
return typesDataIndex() + 1; 参数节偏移+1 参数节第一个int是返回值因此+1
}
const char *QMetaMethodPrivate::rawReturnTypeName() const
{
Q_ASSERT(priv(mobj->d.data)->revision >= 7);
uint typeInfo = mobj->d.data[typesDataIndex()]; 参数节的第一个int 返回值
if (typeInfo & IsUnresolvedType) // IsUnresolvedType = 0x80000000 未解决的类型
return rawStringData(mobj, typeInfo & TypeNameIndexMask);
else
return QMetaType::typeName(typeInfo); 如果是QMetaType内建的用typeName 转换
}
6、uint QMetaMethodPrivate::parameterTypeInfo(int index) const 返回第index个参数的int值 index=-1时是返回值
uint QMetaMethodPrivate::parameterTypeInfo(int index) const
{
Q_ASSERT(priv(mobj->d.data)->revision >= 7);
return mobj->d.data[parametersDataIndex() + index]; 节首地址+Index
}
int QMetaMethodPrivate::parameterType(int index) const
{
Q_ASSERT(priv(mobj->d.data)->revision >= 7);
return typeFromTypeInfo(mobj, parameterTypeInfo(index));
}
static inline int typeFromTypeInfo(const QMetaObject *mo, uint typeInfo)
{
if (!(typeInfo & IsUnresolvedType))
return typeInfo;
return QMetaType::type(stringData(mo, typeInfo & TypeNameIndexMask));
}
8、int QMetaMethodPrivate:: returnType() const 返回 函数返回值的QMetaType值
int QMetaMethodPrivate::returnType() const
{
return parameterType(-1);
}
9、void QMetaMethodPrivate::getParameterTypes(int *types) const 传递一个字节数组 用函数每一个参数的QMetaType值 填充这个数组
void QMetaMethodPrivate::getParameterTypes(int *types) const
{
Q_ASSERT(priv(mobj->d.data)->revision >= 7);
int dataIndex = parametersDataIndex(); 函数参数节偏移
int argc = parameterCount(); 参数个数
for (int i = 0; i < argc; ++i) {
int id = typeFromTypeInfo(mobj, mobj->d.data[dataIndex++]); 获取每一个参数的QMetaType值
*(types++) = id;
}
}
10、QList<QByteArray> QMetaMethodPrivate:: parameterTypes() const 将函数类型名字符串 加入到QList<QByteArray>链表中
QList<QByteArray> QMetaMethodPrivate::parameterTypes() const
{
Q_ASSERT(priv(mobj->d.data)->revision >= 7);
int argc = parameterCount();
QList<QByteArray> list;
list.reserve(argc);
int paramsIndex = parametersDataIndex();
for (int i = 0; i < argc; ++i)
list += typeNameFromTypeInfo(mobj, mobj->d.data[paramsIndex + i]);
return list;
}
11、QList<QByteArray> QMetaMethodPrivate::parameterNames()const 获取参数的形参名 放入链表 形参名的索引放在参数节首地址+参数个数
QList<QByteArray> QMetaMethodPrivate::parameterNames() const
{
Q_ASSERT(priv(mobj->d.data)->revision >= 7);
int argc = parameterCount();
QList<QByteArray> list;
list.reserve(argc);
int namesIndex = parametersDataIndex() + argc;
for (int i = 0; i < argc; ++i)
list += stringData(mobj, mobj->d.data[namesIndex + i]); //stringData根据索引在字符串Block中找到对应的QByteArray
return list;
}
12、QByteArray QMetaMethodPrivate::tag() const 获取函数节的标签值 标签值位于节的第4个int
QByteArray QMetaMethodPrivate::tag() const
{
Q_ASSERT(priv(mobj->d.data)->revision >= 7);
return stringData(mobj, mobj->d.data[handle + 3]);
}
13、QByteArray QMetaMethodPrivate::signature() const 获取函数名字符串 参数类型名字符串链表 然后合成 一个信号用的函数字符串 不带参数名 只有类型名
QByteArray QMetaMethodPrivate::signature() const
{
Q_ASSERT(priv(mobj->d.data)->revision >= 7);
QByteArray result;
result.reserve(256);
result += name(); 获取函数名字符串
result += '(';
QList<QByteArray> argTypes = parameterTypes(); 获取参数字符串
for (int i = 0; i < argTypes.size(); ++i) {
if (i)
result += ',';
result += argTypes.at(i);
}
result += ')';
return result;
}
14、QMetaMethod 的很多函数 中转调用了QMetaMethodPrivate的内联函数来实现其功能,因为父类和子类的对象模型是一样的。
QByteArray QMetaMethod::methodSignature() const
{
if (!mobj)
return QByteArray();
return QMetaMethodPrivate::get(this)->signature();
}
QByteArray QMetaMethod::name() const
{
if (!mobj)
return QByteArray();
return QMetaMethodPrivate::get(this)->name();
}
int QMetaMethod::returnType() const
{
if (!mobj)
return QMetaType::UnknownType;
return QMetaMethodPrivate::get(this)->returnType();
}
int QMetaMethod::parameterCount() const
{
if (!mobj)
return 0;
return QMetaMethodPrivate::get(this)->parameterCount();
}
int QMetaMethod::parameterType(int index) const
{
if (!mobj || index < 0)
return QMetaType::UnknownType;
if (index >= QMetaMethodPrivate::get(this)->parameterCount())
return QMetaType::UnknownType;
int type = QMetaMethodPrivate::get(this)->parameterType(index);
if (type != QMetaType::UnknownType)
return type;
void *argv[] = { &type, &index };
mobj->static_metacall(QMetaObject::RegisterMethodArgumentMetaType, QMetaMethodPrivate::get(this)->ownMethodIndex(), argv);
if (type != -1)
return type;
return QMetaType::UnknownType;
}
void QMetaMethod::getParameterTypes(int *types) const
{
if (!mobj)
return;
QMetaMethodPrivate::get(this)->getParameterTypes(types);
}
QList<QByteArray> QMetaMethod::parameterTypes() const
{
if (!mobj)
return QList<QByteArray>();
return QMetaMethodPrivate::get(this)->parameterTypes();
}
QList<QByteArray> QMetaMethod::parameterNames() const
{
QList<QByteArray> list;
if (!mobj)
return list;
return QMetaMethodPrivate::get(this)->parameterNames();
}
const char *QMetaMethod::typeName() const
{
if (!mobj)
return 0;
return QMetaMethodPrivate::get(this)->rawReturnTypeName();
}
const char *QMetaMethod::tag() const
{
if (!mobj)
return 0;
return QMetaMethodPrivate::get(this)->tag().constData();
}
15、QMetaMethod 特有的方法:
int QMetaMethod::attributes() const
{
if (!mobj)
return false;
return ((mobj->d.data[handle + 4])>>4);
}
返回函数的类型
int QMetaMethod::methodIndex() const
{
if (!mobj)
return -1;
return QMetaMethodPrivate::get(this)->ownMethodIndex() + mobj->methodOffset();
}
返回继承+自由函数组中的索引
QMetaMethod::Access QMetaMethod::access() const
{
if (!mobj)
return Private;
return (QMetaMethod::Access)(mobj->d.data[handle + 4] & AccessMask);
}
返回函数的访问权限 enum Access { Private, Protected, Public }; flags&AccessMask
enum MethodFlags {
AccessPrivate = 0x00,
AccessProtected = 0x01,
AccessPublic = 0x02,
AccessMask = 0x03, //mask
MethodMethod = 0x00,
MethodSignal = 0x04,
MethodSlot = 0x08,
MethodConstructor = 0x0c,
MethodTypeMask = 0x0c,
MethodCompatibility = 0x10,
MethodCloned = 0x20,
MethodScriptable = 0x40,
MethodRevisioned = 0x80
};
QMetaMethod::MethodType QMetaMethod::methodType() const
{
if (!mobj)
return QMetaMethod::Method;
return (QMetaMethod::MethodType)((mobj->d.data[handle + 4] & MethodTypeMask)>>2);
}
返回 函数的类型 信号 槽或其他类型
16、QMetaMethod QMetaMethod::fromSignalImpl(const QMetaObject *metaObject, void **signal) 根据信号函数的指针 返回一个QMetaMethod
MOC生成的static_metacall 示例
void Widget::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
Widget *_t = static_cast<Widget *>(_o);
Q_UNUSED(_t)
switch (_id) {
case 0: _t->TestSignal1((*reinterpret_cast< QString(*)>(_a[1]))); break;
case 1: _t->TestSignal2((*reinterpret_cast< QString(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break;
case 2: _t->TestSignal3(); break;
case 3: _t->TestSlot((*reinterpret_cast< QString(*)>(_a[1]))); break;
case 4: _t->MethodTest((*reinterpret_cast< QString(*)>(_a[1])),(*reinterpret_cast< int(*)>(_a[2]))); break;
default: ;
}
} else if (_c == QMetaObject::IndexOfMethod) { // 如果是查询函数索引
int *result = reinterpret_cast<int *>(_a[0]); _a[0]存放查询结果
void **func = reinterpret_cast<void **>(_a[1]); -a[1]是要查询的函数的内存地址
1 {
typedef void (Widget::*_t)(QString & );
if (*reinterpret_cast<_t *>(func) == static_cast<_t>(&Widget::TestSignal1)) { 如果地址匹配
*result = 0; 将索引放入_a[0]
return;
}
}
{
typedef void (Widget::*_t)(QString & , int );
if (*reinterpret_cast<_t *>(func) == static_cast<_t>(&Widget::TestSignal2)) {
*result = 1;
return;
}
}
{
typedef void (Widget::*_t)();
if (*reinterpret_cast<_t *>(func) == static_cast<_t>(&Widget::TestSignal3)) {
*result = 2;
return;
}
}
}
QMetaMethod QMetaMethod::fromSignalImpl(const QMetaObject *metaObject, void **signal)
{
int i = -1;
void *args[] = { &i, signal }; i来返回查询结果 *signal 信号函数内存地址
QMetaMethod result;
for (const QMetaObject *m = metaObject; m; m = m->d.superdata) {
m->static_metacall(QMetaObject::IndexOfMethod, 0, args); 参见下面的QMetaObject::static_metacall
if (i >= 0) {
result.mobj = m; 如果返回了索引
result.handle = priv(m->d.data)->methodData + 5*i; 用索引定位Handle 构建QmetaMethod
break;
}
}
return result;
}
int QMetaObject::static_metacall(Call cl, int idx, void **argv) const
{
Q_ASSERT(priv(d.data)->revision >= 6);
if (!d.static_metacall)
return 0;
d.static_metacall(0, cl, idx, argv);
return -1;
}
17、bool QMetaMethod::invoke 调用该函数
bool QMetaMethod::invoke(QObject *object,
Qt::ConnectionType connectionType,
QGenericReturnArgument returnValue,
QGenericArgument val0,
QGenericArgument val1,
QGenericArgument val2,
QGenericArgument val3,
QGenericArgument val4,
QGenericArgument val5,
QGenericArgument val6,
QGenericArgument val7,
QGenericArgument val8,
QGenericArgument val9) const
{
if (!object || !mobj)
return false;
Q_ASSERT(mobj->cast(object));
// check return type
if (returnValue.data()) {
const char *retType = typeName();
if (qstrcmp(returnValue.name(), retType) != 0) {
// normalize the return value as well
QByteArray normalized = QMetaObject::normalizedType(returnValue.name());
if (qstrcmp(normalized.constData(), retType) != 0) {
// String comparison failed, try compare the metatype.
int t = returnType();
if (t == QMetaType::UnknownType || t != QMetaType::type(normalized))
return false;
}
}
} //判断返回值类型是否匹配
// check argument count (we don't allow invoking a method if given too few arguments)
const char *typeNames[] = {
returnValue.name(),
val0.name(),
val1.name(),
val2.name(),
val3.name(),
val4.name(),
val5.name(),
val6.name(),
val7.name(),
val8.name(),
val9.name()
}; //参数类型字符串数组
int paramCount;
for (paramCount = 1; paramCount < MaximumParamCount; ++paramCount) {
if (qstrlen(typeNames[paramCount]) <= 0)
break; //实际传过来的可用参数个数
}
if (paramCount <= QMetaMethodPrivate::get(this)->parameterCount()) 如果传过来的参数小于函数所需参数 返回失败
return false;
// check connection type
QThread *currentThread = QThread::currentThread();
QThread *objectThread = object->thread();
if (connectionType == Qt::AutoConnection) {
connectionType = currentThread == objectThread
? Qt::DirectConnection
: Qt::QueuedConnection; 设置链接类型。如果为AutoConnection,则判断调用线程和对象所处线程是不是同一个
} 是的话设置为直接调用,不是的话设置为队列调用
#ifdef QT_NO_THREAD
if (connectionType == Qt::BlockingQueuedConnection) {
connectionType = Qt::DirectConnection;
}
#endif
// invoke!
void *param[] = {
returnValue.data(),
val0.data(),
val1.data(),
val2.data(),
val3.data(),
val4.data(),
val5.data(),
val6.data(),
val7.data(),
val8.data(),
val9.data()
}; 参数值数组
int idx_relative = QMetaMethodPrivate::get(this)->ownMethodIndex(); 相对于自身索引
int idx_offset = mobj->methodOffset(); //想对于继承过来的函数的偏移
Q_ASSERT(QMetaObjectPrivate::get(mobj)->revision >= 6);
QObjectPrivate::StaticMetaCallFunction callFunction = mobj->d.static_metacall;
if (connectionType == Qt::DirectConnection) {
if (callFunction) {
callFunction(object, QMetaObject::InvokeMetaMethod, idx_relative, param);
return true;
} else {
return QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, idx_relative + idx_offset, param) < 0; 调用静态metacall或者动态call
}
} else if (connectionType == Qt::QueuedConnection) {
if (returnValue.data()) {
qWarning("QMetaMethod::invoke: Unable to invoke methods with return values in "
"queued connections");
return false;
} 如果是队列方式,不能有返回值
int nargs = 1; // include return type
void **args = (void **) malloc(paramCount * sizeof(void *));
Q_CHECK_PTR(args);
int *types = (int *) malloc(paramCount * sizeof(int));
Q_CHECK_PTR(types);
types[0] = 0; // return type
args[0] = 0;
for (int i = 1; i < paramCount; ++i) {
types[i] = QMetaType::type(typeNames[i]);
if (types[i] != QMetaType::UnknownType) {
args[i] = QMetaType::create(types[i], param[i]);
++nargs;
} else if (param[i]) {
// Try to register the type and try again before reporting an error.
void *argv[] = { &types[i], &i };
QMetaObject::metacall(object, QMetaObject::RegisterMethodArgumentMetaType,
idx_relative + idx_offset, argv);
if (types[i] == -1) {
qWarning("QMetaMethod::invoke: Unable to handle unregistered datatype '%s'",
typeNames[i]);
for (int x = 1; x < i; ++x) {
if (types[x] && args[x])
QMetaType::destroy(types[x], args[x]);
}
free(types);
free(args);
return false;
}
}
} 复制参数
加入事件队列
QCoreApplication::postEvent(object, new QMetaCallEvent(idx_offset, idx_relative, callFunction,
0, -1, nargs, types, args));
} else { // blocking queued connection
#ifndef QT_NO_THREAD
if (currentThread == objectThread) {
qWarning("QMetaMethod::invoke: Dead lock detected in "
"BlockingQueuedConnection: Receiver is %s(%p)",
mobj->className(), object);
}
QSemaphore semaphore;
QCoreApplication::postEvent(object, new QMetaCallEvent(idx_offset, idx_relative, callFunction,
0, -1, 0, 0, param, &semaphore));
semaphore.acquire();
#endif // QT_NO_THREAD
}
return true;
}