当前位置: 首页 > 工具软件 > MOC > 使用案例 >

Qt Moc及信号-槽源代码解析

燕和裕
2023-12-01

版本Qt5.12.3 moc_test.cpp位于可执行文件目录下,其余源代码都位于Qt5.12.3\5.12.3\Src\qtbase\src\corelib\kernel

一. MOC

1.1 简介

元对象编译器moc(Meta-Object Compiler)是Qt对C++的扩展。可以先把它看作一个代码生成器。以test类为例,构建项目时,moc读取C++头文件。如果在test.h中找到Q_OBJECT宏,它将生成一个moc_test.cpp,其中包含test类的元对象(metaObject)代码。这个新的文件和test.cpp一起参与编译,最终被链接到二进制代码中去。

Qt 将源代码交给标准 C++编译器,如gcc之前,需要事先将扩展的语法(Q_OBJECT,SLOT,SIGNAL等)展开来。完成这一操作的就是moc。

可以在命令行下输入moc test.h -o moc_test.cpp手动生成。

1.2 宏

Q_OBJECT,SLOT,SIGNAL,emit, Q_INVOKABLE等宏是Qt扩展的语法,它们其实定义在qobjectdefs.h中,编译时被moc展开。

二. moc_test.cpp分析

先贴一下代码:

test.h

class test : public QObject
{
    Q_OBJECT
public:
    explicit test(QObject *parent = nullptr);
    int getValue(){return m_value;}
    Q_INVOKABLE void identifyByMoc();

signals:
    void testSignal1();
    void testSignal2();
    void testSignal3();
    void valueChanged(int newValue);
    
public slots:
    void testSlot1();
    void testSlot2();
    void setValue(int value);

private:
    int m_value;

};

test.cpp

#include "test.h"

test::test(QObject *parent) : QObject(parent)
{
    m_value = 0;
}

void test::identifyByMoc(){
    qDebug()<<"Identified By Moc";
}

void test::testSlot1(){
    qDebug()<<"Invoke testSlot1";
}

void test::testSlot2(){
    qDebug()<<"Invoke testSlot2";
}

void test::setValue(int value)
{
    m_value = value;
    emit valueChanged(value);
}

main.cpp

#include “test.h”

void test_value()
{

    test a,b;
    QObject::connect(&a,SIGNAL(valueChanged(int)),&b,SLOT(setValue(int)));
    QObject::connect(&a,SIGNAL(valueChanged(int)),&a,SLOT(testSlot1()));
    qDebug()<<SIGNAL(valueChanged(int))<<SLOT(setValue(int));
    qDebug()<<"before: b.getValue ="<<b.getValue();
    a.setValue(12);
    qDebug()<<"after: b.getValue ="<<b.getValue();
}

moc_test.cpp

/****************************************************************************
** Meta object code from reading C++ file 'test.h'
**
** Created by: The Qt Meta Object Compiler version 67 (Qt 5.12.3)
**
** WARNING! All changes made in this file will be lost!
*****************************************************************************/
#include "../../mocTest/test.h"
#include <QtCore/qbytearray.h>
#include <QtCore/qmetatype.h>
#if !defined(Q_MOC_OUTPUT_REVISION)
#error "The header file 'test.h' doesn't include <QObject>."
#elif Q_MOC_OUTPUT_REVISION != 67
#error "This file was generated using the moc from 5.12.3. It"
#error "cannot be used with the include files from this version of Qt."
#error "(The moc has changed too much.)"
#endif

QT_BEGIN_MOC_NAMESPACE
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED

//此处省略见下文

QT_WARNING_POP
QT_END_MOC_NAMESPACE

moc_test.cpp看起来很复杂,分三部分来看:

2.1 类信息

位于moc_test.cpp头部

struct qt_meta_stringdata_test_t { //定义保存类信息的结构体
    QByteArrayData data[12];
    char stringdata0[113];
};

QT_MOC_LITERAL宏的作用是为stringdata0中保存的每个函数名都创建一个QByteArrayData,宏参数为函数的索引值,偏移量,函数名长度。

#define QT_MOC_LITERAL(idx, ofs, len \
Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
qptrdiff(offsetof(qt_meta_stringdata_test_t, stringdata0) + ofs \
- idx * sizeof(QByteArrayData)) \
)
static const qt_meta_stringdata_test_t
qt_meta_stringdata_test = { //初始化保存类信息的结构体
{
QT_MOC_LITERAL(0, 0, 4), // "test"
QT_MOC_LITERAL(1, 5, 11), // "testSignal1"
QT_MOC_LITERAL(2, 17, 0), // ""
QT_MOC_LITERAL(3, 18, 11), //"testSignal2"
QT_MOC_LITERAL(4, 30, 11), //"testSignal3"
QT_MOC_LITERAL(5, 42, 12), // "valueChanged"
QT_MOC_LITERAL(6, 55, 8), //"newValue"
QT_MOC_LITERAL(7, 64, 9), //"testSlot1"
QT_MOC_LITERAL(8, 74, 9), //"testSlot2"
QT_MOC_LITERAL(9, 84, 8), //"setValue"
QT_MOC_LITERAL(10, 93, 5), //"value"
QT_MOC_LITERAL(11, 99, 13) //"identifyByMoc
},
"test\0testSignal1\0\0testSignal2\0testSignal3\0"
"valueChanged\0newValue\0testSlot1\0"
"testSlot2\0setValue\0value\0identifyByMoc"
};
#undef QT_MOC_LITERAL

static const uint qt_meta_data_test[] = {
//保存了信号,槽及moc识别的其他函数的个数,函数索引,返回类型,参数个数,参数类型等信息。

 //content:
      8,       // revision
      0,       // classname
      0,    0, // classinfo
      8,   14, // methods
      0,    0, // properties
      0,    0, // enums/sets
      0,    0, // constructors
      0,       // flags
      4,       // signalCount
 
 //signals: name, argc, parameters, tag, flags
      1,    0,   54,   2, 0x06 /* Public */,
      3,    0,   55,   2, 0x06 /* Public */,
      4,    0,   56,   2, 0x06 /* Public */,
      5,    1,   57,   2, 0x06 /* Public */,
 
 //slots: name, argc, parameters, tag, flags
      7,    0,   60,   2, 0x0a /* Public */,
      8,    0,   61,   2, 0x0a /* Public */,
      9,    1,   62,   2, 0x0a /* Public */,
 
 //methods: name, argc, parameters, tag, flags
     11,    0,   65,   2, 0x02 /* Public */,
 
 //signals: parameters
   QMetaType::Void,
   QMetaType::Void,
   QMetaType::Void,
   QMetaType::Void, QMetaType::Int,   6,
 
 //slots: parameters
   QMetaType::Void,
   QMetaType::Void,
   QMetaType::Void, QMetaType::Int,  10,
 
 //methods: parameters
   QMetaType::Void,
 
      0        // eod
};

2.2 signals实现

位于moc_test.cpp底部:

// SIGNAL 0
void test::testSignal1()
{
    QMetaObject::activate(this, &staticMetaObject, 0, nullptr);
}
 
// SIGNAL 1
void test::testSignal2()
{
    QMetaObject::activate(this, &staticMetaObject, 1, nullptr);
}
 
// SIGNAL 2
void test::testSignal3()
{
    QMetaObject::activate(this, &staticMetaObject, 2, nullptr);
}
 
// SIGNAL 3
void test::valueChanged(int _t1)
{
    void *_a[] = { nullptr,const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
    QMetaObject::activate(this, &staticMetaObject, 3, _a);
}

test.h中构造函数一个,普通函数一个(getValue),signal四个,slot三个,Q_INVOKABLE修饰的方法一个。其中三个槽函数需要自己在test.cpp里实现,四个信号函数由moc自动在moc_test.cpp中实现,在注释可以看到索引根据声明顺序分别为0,1,2,3。

2.3 Q_OBJECT宏的展开

查找qobjectdefs.h,可以找到Q_OBJECT宏的定义

#define Q_OBJECT \
public: \
   QT_WARNING_PUSH \
   Q_OBJECT_NO_OVERRIDE_WARNING \
   static const QMetaObject staticMetaObject; \
   virtual const QMetaObject *metaObject() const; \
   virtual void *qt_metacast(const char *); \
   virtual int qt_metacall(QMetaObject::Call, int, void **); \
   QT_TR_FUNCTIONS \
private: \
   Q_OBJECT_NO_ATTRIBUTES_WARNING \
   Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *,QMetaObject::Call, int, void **); \
   QT_WARNING_POP \
   
struct QPrivateSignal {}; \
QT_ANNOTATE_CLASS(qt_qobject,
"")

正对应moc_test.cpp里的函数等,我们取重要的几个:
位于moc_test.cpp中部:

2.3.1 qt_static_metacall

void test::qt_static_metacall(QObject *_o,QMetaObject::Call _c, int _id, void **_a)
{
   if (_c == QMetaObject::InvokeMetaMethod) {
       auto *_t = static_cast<test *>(_o);
       Q_UNUSED(_t)
       switch (_id) {
       case 0: _t->testSignal1(); break;
       case 1: _t->testSignal2(); break;
       case 2: _t->testSignal3(); break;
       case 3: _t->valueChanged((*reinterpret_cast< int(*)>(_a[1])));break;
       case 4: _t->testSlot1(); break;
       case 5: _t->testSlot2(); break;
       case 6: _t->setValue((*reinterpret_cast< int(*)>(_a[1])));break;
       case 7: _t->identifyByMoc(); break;
       default: ;
       }
    }else if (_c == QMetaObject::IndexOfMethod) {
       int *result = reinterpret_cast<int *>(_a[0]);
       {
           using _t = void (test::*)();
           if (*reinterpret_cast<_t *>(_a[1]) ==static_cast<_t>(&test::testSignal1)) {
                *result = 0;
                return;
           }
       }
       {
           using _t = void (test::*)();
           if (*reinterpret_cast<_t*>(_a[1]) == static_cast<_t>(&test::testSignal2)) {
                *result = 1;
                return;
           }
       }
       {
           using _t = void (test::*)();
           if (*reinterpret_cast<_t *>(_a[1]) ==
static_cast<_t>(&test::testSignal3)) {
                *result = 2;
                return;
           }
       }
       {
           using _t = void (test::*)(int );
           if (*reinterpret_cast<_t *>(_a[1]) ==
static_cast<_t>(&test::valueChanged)) {
                *result = 3;
                return;
           }
       }
    }
}

根据函数索引调用槽函数,在这里可以看出信号函数也可以当作槽函数一样被调用,这也是信号槽调用过程的最后一步(先留个印象)

2.3.2 staticMetaObject

test类的元对象(QMetaObject),保存了test类的信息。保存的数据qt_meta_stringdata_test.data及qt_meta_data_test在moc文件的顶部定义并初始化。

QT_INIT_METAOBJECT const QMetaObject test::staticMetaObject = { {
   &QObject::staticMetaObject,
   qt_meta_stringdata_test.data,
   qt_meta_data_test,
   qt_static_metacall,
   nullptr,
   nullptr
} };

2.3.3 metaObject

返回当前的QMetaObject,一般是返回staticMetaObject,即2介绍的。

const QMetaObject *test::metaObject() const
{
   return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
}

2.3.4 qt_metacast

类型转换

void *test::qt_metacast(const char *_clname)
{
   if (!_clname) return nullptr;
   if (!strcmp(_clname, qt_meta_stringdata_test.stringdata0))
       return static_cast<void*>(this);
   return QObject::qt_metacast(_clname);
}

2.3.5 qt_metacall

int test::qt_metacall(QMetaObject::Call _c,int _id, void **_a)
{
   _id = QObject::qt_metacall(_c, _id, _a);
   if (_id < 0)
       return _id;
   if (_c == QMetaObject::InvokeMetaMethod) {
       if (_id < 8)
           qt_static_metacall(this, _c, _id, _a);
       _id -= 8;
   }else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
       if (_id < 8)
           *reinterpret_cast<int*>(_a[0]) = -1;
       _id -= 8;
   }
   return _id;
}

在内部调用了qt_static_metacall

总结:Moc的作用就是把Q_OBJECT SIGNAL Q_INVOKABLE等宏展开,并保存类中特定函数(signals,slots标签下的函数及Q_INVOKABLE修饰的函数等)的信息,创建函数的回调。

三. connect

要使用Qt的信号-槽机制,必须要connect这一步。我们查看QObject::connect的源码:
QObject.cpp

QMetaObject::Connection
QObject::connect(const QObject *sender, const char *signal,
                                     constQObject *receiver, const char *method, Qt::ConnectionType type)
{
//此处省略了函数参数检查,信号及槽函数索引获取,connect类型处理等代码。
//最后其实调用了QMetaObjectPrivate::connect
   QMetaObject::Connection handle = QMetaObject::Connection(QMetaObjectPrivate::connect(
        sender, signal_index, smeta, receiver, method_index_relative, rmeta ,type, types));
   return handle;
}

QMetaObjectPrivate::connect同样位于QObject.cpp

QObjectPrivate::Connection *QMetaObjectPrivate::connect(const QObject *sender,
                                 int signal_index, const QMetaObject *smeta,
                                 const QObject *receiver, int method_index,
                                 const QMetaObject *rmeta, int type, int *types)
{
   QObject *s = const_cast<QObject *>(sender);
   QObject *r = const_cast<QObject *>(receiver);
 
   int method_offset = rmeta ? rmeta->methodOffset() : 0;
   Q_ASSERT(!rmeta || QMetaObjectPrivate::get(rmeta)->revision >= 6);
   QObjectPrivate::StaticMetaCallFunction callFunction =
       rmeta ? rmeta->d.static_metacall : 0;
 
   QOrderedMutexLocker locker(signalSlotLock(sender),
                              signalSlotLock(receiver));
 
   if (type & Qt::UniqueConnection) {
       QObjectConnectionListVector *connectionLists =QObjectPrivate::get(s)->connectionLists;
       if (connectionLists && connectionLists->count() >signal_index) {
           const QObjectPrivate::Connection *c2 = (*connectionLists)[signal_index].first;
           int method_index_absolute = method_index + method_offset;
           while (c2) {
                if (!c2->isSlotObject && c2->receiver == receiver && c2->method() == method_index_absolute)
                    return 0;
                c2 = c2->nextConnectionList;
           }
       }
       type &= Qt::UniqueConnection - 1;
    }
 
// QObjectPrivate::Connection实例化,
//存储了信号-槽链接的信息
   QScopedPointer<QObjectPrivate::Connection> c(new QObjectPrivate::Connection);
   c->sender = s;
   c->signal_index = signal_index;
   c->receiver = r;
   c->method_relative = method_index;
   c->method_offset = method_offset;
   c->connectionType = type;
   c->isSlotObject = false;
   c->argumentTypes.store(types);
   c->nextConnectionList = 0;
   c->callFunction = callFunction;
 
    //addConnection为信号发送者s保存了这个信号-槽链接,具体保存了什么,还需要
    //分析QObjectPrivate::Connection以及QObjectPrivate::addConnection
   QObjectPrivate::get(s)->addConnection(signal_index, c.data());
 
   locker.unlock();
   QMetaMethod smethod = QMetaObjectPrivate::signal(smeta, signal_index);
   if (smethod.isValid())
       s->connectNotify(smethod);
 
   return c.take();
}

qobject_p.h中定义了class QObjectPrivate
它的几个成员如下:

struct Connection
{
       QObject *sender;
       QObject *receiver;
       union {
           StaticMetaCallFunction callFunction;
           QtPrivate::QSlotObjectBase *slotObj;
       };
       // The next pointer for the singly-linked ConnectionList
       Connection *nextConnectionList;
       //senders linked list
       Connection *next;
       Connection **prev;
       ushort method_offset;
       ushort method_relative;
       uint signal_index : 27; // In signal range (see QObjectPrivate::signalIndex())
       ushort connectionType : 3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking
       //省略部分代码
};

Connection结构体保存了一个连接。其中的信息包括信号发送者指针,信号接收者指针以及指向下一个Connection的指针,信号索引,连接类型等

一个信号可以对应多个槽函数,这里用ConnectionList保存一个信号对应的所有连接。它是一个单向链表,每个节点都是一个Connection,通过它内部的nextConnectionList指针指向下一个Connection。在这里仅保存头尾指针即可。

struct ConnectionList {
       ConnectionList() : first(nullptr), last(nullptr) {}
       Connection *first;
       Connection *last;
};

connectionLists保存此对象作为信号发送者所对应的所有连接。这个向量里每个元素都是一个ConnectionList单链表

QObjectConnectionListVector *connectionLists;

QObject.cpp里定义了QObjectConnectionListVector

class QObjectConnectionListVector : public
QVector<QObjectPrivate::ConnectionList>
{
public:
   bool orphaned; //the QObject owner of this vector has been destroyed while the vector was inUse
   bool dirty; //some Connection have been disconnected (their receiver is 0) but not removed from the list yet
   int inUse; //number of functions that are currently accessing this object or its connections
   QObjectPrivate::ConnectionList allsignals;
 
   QObjectConnectionListVector(): QVector<QObjectPrivate::ConnectionList>(), orphaned(false),
dirty(false), inUse(0)
   {}
 
   QObjectPrivate::ConnectionList &operator[](int at)
   {
       if (at < 0)
           return allsignals;
       return QVector<QObjectPrivate::ConnectionList>::operator[](at);
   }
};

Connection *next和Connection**prev是此对象作为信号接收者时,保存发送者的双向链表的操作指针,这里的内容待以后补充。

接下来看最后的addConnection, 位于QObject.cpp

void QObjectPrivate::addConnection(int signal, Connection *c)
{
   Q_ASSERT(c->sender == q_ptr);
   if (!connectionLists)
       connectionLists = new QObjectConnectionListVector();
   if (signal >= connectionLists->count())
       connectionLists->resize(signal + 1);
 
   //根据信号索引取得此信号所对应的链表,并把此连接加入链表中。
   ConnectionList &connectionList = (*connectionLists)[signal];
   if (connectionList.last) {
       connectionList.last->nextConnectionList = c;
   }else {
       connectionList.first = c;
   }
   connectionList.last = c;

   cleanConnectionLists();
 
   //下面是对Connection* QObjectPrivate::senders双向链表的操作
   c->prev = &(QObjectPrivate::get(c->receiver)->senders);
   c->next = *c->prev;
   *c->prev = c;
   if (c->next)
       c->next->prev = &c->next;
 
   if (signal < 0) {
       connectedSignals[0] = connectedSignals[1] = ~0;
   }else if (signal < (int)sizeof(connectedSignals) * 8) {
       connectedSignals[signal >> 5] |= (1 << (signal & 0x1f));
   }
}

四. activate

连接完成后,我们调用信号函数,从moc_test.cpp里对信号函数的实现可知,其实是调用了QMetaObject::activate(this, &staticMetaObject, 3, _a);

// SIGNAL 3
void test::valueChanged(int _t1)
{
   void *_a[] = { nullptr, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
   QMetaObject::activate(this, &staticMetaObject, 3, _a);
}

QMetaObject::activate源码在QObject.cpp中

void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_signal_index, void **argv)
{
   activate(sender, QMetaObjectPrivate::signalOffset(m), local_signal_index, argv);
}

下面的activate函数省略了部分代码,方便理解。

void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_index, void **argv)
{
    int signal_index = signalOffset + local_signal_index;
 
    //判断是否有与该信号相连接的接收对象
    if(!sender->d_func()->isSignalConnected(signal_index))
        return; // nothing connected to these signals, and no spy
    //给信号量加锁,因为在connectionLists里所有的操作都是线程安全的
    QMutexLocker locker(signalSlotLock(sender));
 
    //获取与该信号的ConnectionList链表
    QObjectConnectionListVector *connectionLists = sender->d_func()->connectionLists;
    const QObjectPrivate::ConnectionList *list = &connectionLists->at(signal_index);
    QObjectPrivate::Connection *c = list->first;
    if (!c) continue;
    QObjectPrivate::Connection *last = list->last;
 
    //循环执行该信号对应的所有槽函数
    do {
        if (!c->receiver)
            continue;
 
        QObject * const receiver = c->receiver;
        const bool receiverInSameThread = QThread::currentThreadId() == receiver->d_func()->threadData->threadId;
 
        // 决定该连接是马上响应还是把它放到事件队列中
        if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)|| (c->connectionType == Qt::QueuedConnection)) {
            queued_activate(sender, signal_index, c, argv);
            continue;
        } else if (c->connectionType == Qt::BlockingQueuedConnection) {
            continue;
        }
        QConnectionSenderSwitcher sw;
        if (receiverInSameThread)
            sw.switchSender(receiver, sender, signal_index);
 
        const QObjectPrivate::StaticMetaCallFunction callFunction = c->callFunction;
  
        const int method_relative = c->method_relative;
        //下面if-else结构包含三种调用槽函数的方式。
        if (c->isSlotObject) {
                c->slotObj->ref();
                QScopedPointer<QtPrivate::QSlotObjectBase,QSlotObjectBaseDeleter>obj(c->slotObj);
 
                locker.unlock();
                Q_TRACE(QMetaObject_activate_begin_slot_functor, obj.data());
                //一,通过call调用接收者中的槽函数
                obj->call(receiver, argv ? argv : empty_argv);
                Q_TRACE(QMetaObject_activate_end_slot_functor, obj.data());
 
                obj.reset();
 
                locker.relock();
            } else if (c->callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) {
                const int methodIndex = c->method();
                const int method_relative = c->method_relative;
                const auto callFunction = c->callFunction;
                locker.unlock();
                if(qt_signal_spy_callback_set.slot_begin_callback != 0)
                    qt_signal_spy_callback_set.slot_begin_callback(receiver, methodIndex, argv ? argv : empty_argv);
                Q_TRACE(QMetaObject_activate_begin_slot, receiver, methodIndex);
                //二,callFunction即moc_test.cpp里的qt_static_metacall
 
                callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv ? argv : empty_argv);
 
                Q_TRACE(QMetaObject_activate_end_slot, receiver, methodIndex);
                if(qt_signal_spy_callback_set.slot_end_callback != 0)
                   qt_signal_spy_callback_set.slot_end_callback(receiver, methodIndex);
                locker.relock();
            } else {
                const int method = c->method_relative + c->method_offset;
                locker.unlock();
 
                if(qt_signal_spy_callback_set.slot_begin_callback != 0) {
                qt_signal_spy_callback_set.slot_begin_callback(receiver, method,argv ? argv : empty_argv);
                }
                Q_TRACE(QMetaObject_activate_begin_slot, receiver, method);
                //三,metacall即moc_test.cpp里的qt_metacall
                metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
 
                Q_TRACE(QMetaObject_activate_end_slot, receiver, method);
                if(qt_signal_spy_callback_set.slot_end_callback != 0)
                    qt_signal_spy_callback_set.slot_end_callback(receiver,method);
 
                locker.relock();
            }        // 检查该对象没有被槽函数删除
        if (connectionLists->orphaned) break;
    } while (c != last && (c = c->nextConnectionList) != 0);
}

第二种方法解析:
qobjectdefs.h

struct Q_CORE_EXPORT QMetaObject
{
struct { // private data
       const 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;
}

moc_test.cpp 用qt_static_metacall实例化d.static_metacall

QT_INIT_METAOBJECT const QMetaObject
test::staticMetaObject = { {
   &QObject::staticMetaObject,
   qt_meta_stringdata_test.data,
   qt_meta_data_test,
   qt_static_metacall,
   nullptr,
   nullptr
} };

qobject.cpp

QObjectPrivate::Connection *QMetaObjectPrivate::connect()
{
    QObjectPrivate::StaticMetaCallFunction callFunction = rmeta ? rmeta->d.static_metacall : 0;
}
 
void QMetaObject::activate()
{
    const QObjectPrivate::StaticMetaCallFunction callFunction = c->callFunction;
callFunction(...);
//最后调用callFunction其实就是调用qt_static_metacall,还记的文章前边说的留个印象么,现在就到了调用的最后一步。
}

第三种方法解析:
qmetaobject.cpp

int QMetaObject::metacall(QObject *object, Call cl, int idx, void **argv)
{
   if (object->d_ptr->metaObject)
       return object->d_ptr->metaObject->metaCall(object, cl, idx,
argv);
   else
       return object->qt_metacall(cl, idx, argv);
}

moc_test.cpp

int test::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
   _id = QObject::qt_metacall(_c, _id, _a);
   if (_id < 0)
       return _id;
   if (_c == QMetaObject::InvokeMetaMethod) {
       if (_id < 8)
           qt_static_metacall(this, _c, _id, _a);
       _id -= 8;
   }else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
       if (_id < 8)
           *reinterpret_cast<int*>(_a[0]) = -1;
       _id -= 8;
   }
   return _id;
}

qobject.cpp

void QMetaObject::activate()
{
    metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
}

metacall其实就是调用qt_metacall,在内部最终还是调用了qt_static_metacall

五. 总结

5.1 解析

Moc帮我们解析头文件中Qt特有的宏,将函数信息保存在数组中,构建信号函数的实现,槽函数的回调。

5.2 保存

QObject::connect将连接信息保存在结构体Connection中,一个信号可对应多个槽函数,这就形成了单链表ConnectionList,然后以信号在test类的MetaObject中的索引作为向量的索引保存所有链表,形成QObjectConnectionListVector* connectionLists.

5.3 调用

调用信号函数时,其实是调用activate函数,最终回到qt_static_metacall,调用槽函数。

 类似资料: