最全Qt Moc及信号-槽源代码解析_qt_moc_literal(1),讲的真详细

img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新

如果你需要这些资料,可以戳这里获取

//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实例化,
//存储了信号-槽链接的信息
QScopedPointerQObjectPrivate::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
QVectorQObjectPrivate::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(): QVectorQObjectPrivate::ConnectionList(), orphaned(false),
dirty(false), inUse(0)
{}

QObjectPrivate::ConnectionList &operator[](int at)
{
if (at < 0)
return allsignals;
return QVectorQObjectPrivate::ConnectionList::operator;
}
};


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);

}


第二种方法解析:  


**收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。**
![img](https://img-blog.csdnimg.cn/img_convert/8dd7e8af568a73a4bc3f229836edbea4.png)
![img](https://img-blog.csdnimg.cn/img_convert/35523c1086be70983276e330a5269a34.png)

**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618679757)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人**

**都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

_end\_callback(receiver,method);
 
                locker.relock();
            }        // 检查该对象没有被槽函数删除
        if (connectionLists->orphaned) break;
    } while (c != last && (c = c->nextConnectionList) != 0);
}

第二种方法解析:

收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
[外链图片转存中…(img-88nkfJch-1715721023568)]
[外链图片转存中…(img-o8Fwt0V8-1715721023569)]

如果你需要这些资料,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 17
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值