C++中头文件函数中的声明除非是纯虚函数,一般都在对应的cpp文件中有其函数实现,否则就会有undefined reference to XXXXXXXX。但是反观Qt的信号的声明方式:
signals: void mysignal();这里明显是一个函数的声明,但我们也没有在对应的cpp中去实现这个函数,那么这个函数到底是在哪里实现的呢?答案就是:在moc文件中。
下面放上一个信号的声明和对应实现的moc代码。为了排版的紧凑删除了一些空行。
void sigOkclicked(int nIndex);
void sigAddGroup(st1 qtRuleGroup);
void sigAddRule(st2 qtMainRule);//st1和st2分别是自己定义的一个结构体
void sigModifyGroup();
void sigModifyRule();
对应的moc:
// SIGNAL 0
void settingDialog::sigOkclicked(int _t1){
void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
QMetaObject::activate(this, &staticMetaObject, 0, _a);
}
// SIGNAL 1
void settingDialog::sigAddGroup(qt_RuleGroup _t1){
void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
QMetaObject::activate(this, &staticMetaObject, 1, _a);
}
// SIGNAL 2
void settingDialog::sigAddRule(qt_MainRule _t1){
void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
QMetaObject::activate(this, &staticMetaObject, 2, _a);
}
// SIGNAL 3
void settingDialog::sigModifyGroup(){
QMetaObject::activate(this, &staticMetaObject, 3, 0);
}
// SIGNAL 4
void settingDialog::sigModifyRule(){
QMetaObject::activate(this, &staticMetaObject, 4, 0);
}
实现看起来很简单,调用的QMetaObject::activate方法,而这个staticMetaObject 在前一篇文章中提到过他是这个类默认的一个静态元对象。第三个参数是信号对应的序数,至于第四个参数为0代表无参信号,否则就是含参信号,代表相应的参数的指针。看一下Qt中这个方法的实现和其有关的调用QMetaObject::activate():
//位于qobject.cpp,此方法有其对应的N个重载函数,这是内部的实现过程 void QMetaObject::activate(QObject *sender, int signalOffset, int local_signal_index, void **argv) { int signal_index = signalOffset + local_signal_index; //计算信号偏移,一般根据我们的调用情况,这里回去计算信号偏移,信号偏移包括其父类的signals的计算偏移也是要计算的,signalOffset就是,local_signal_index这个就是本地的信号偏移,也就是上面的0,1,2,3,4这些参数。 if (sender->d_func()->blockSig) return; //判断信号是否阻塞,和connect的第五个参数有关 if (sender->d_func()->isDeclarativeSignalConnected(signal_index) && QAbstractDeclarativeData::signalEmitted) { QAbstractDeclarativeData::signalEmitted(sender->d_func()->declarativeData, sender, signal_index, argv); } // //这里排除信号尚未链接和signal相关回调检查出错的情况 if (!sender->d_func()->isSignalConnected(signal_index, /*checkDeclarative =*/ false) && !qt_signal_spy_callback_set.signal_begin_callback && !qt_signal_spy_callback_set.signal_end_callback) { // The possible declarative connection is done, and nothing else is connected, so: return; } //设置信号起始回调 void *empty_argv[] = { 0 }; if (qt_signal_spy_callback_set.signal_begin_callback != 0) { qt_signal_spy_callback_set.signal_begin_callback(sender, signal_index, argv ? argv : empty_argv); } { //开互斥锁,应该是为多线程考虑 QMutexLocker locker(signalSlotLock(sender)); struct ConnectionListsRef { QObjectConnectionListVector *connectionLists; ConnectionListsRef(QObjectConnectionListVector *connectionLists) : connectionLists(connectionLists) { if (connectionLists) ++connectionLists->inUse; } ~ConnectionListsRef() { if (!connectionLists) return; --connectionLists->inUse; Q_ASSERT(connectionLists->inUse >= 0); if (connectionLists->orphaned) { if (!connectionLists->inUse) delete connectionLists; } } QObjectConnectionListVector *operator->() const { return connectionLists; } }; //在函数内部声明了一个struct并重载了其->运算符 ConnectionListsRef connectionLists = sender->d_func()->connectionLists; if (!connectionLists.connectionLists) { locker.unlock(); if (qt_signal_spy_callback_set.signal_end_callback != 0) qt_signal_spy_callback_set.signal_end_callback(sender, signal_index); return; } const QObjectPrivate::ConnectionList *list; if (signal_index count()) list = &connectionLists->at(signal_index); else list = &connectionLists->allsignals; //这里得到所有signals的list。 Qt::HANDLE currentThreadId = QThread::currentThreadId(); //得到当前线程ID do { QObjectPrivate::Connection *c = list->first; if (!c) continue; // We need to check against last here to ensure that signals added // during the signal emission are not emitted in this emission. //看注释即可 QObjectPrivate::Connection *last = list->last; //采用双重循环,外面是遍历所有的信号,内层是拿到信号对应的receiver,有一个信号绑定多个槽的这种情况存在,所以两层。Connection他只保存一个sender和receiver的对应关系 do { //这里是拿到对应的receiver是一个object if (!c->receiver) continue; //这里应该是为了数据安全用了const QObject * const receiver = c->receiver; const bool receiverInSameThread = currentThreadId == receiver->d_func()->threadData->threadId; // determine if this connection should be sent immediately or // put into the event queue //这里看注释,情形就是,当receiver的threadId和sender的threadId一样直接发,否则将这个调用发送到事件循环 //当时autoConnection且不同线程或者第五个参数是QueuedConnection那么是发送到县城循环,因为我们connect不加第五个参数的时候默认是AutoConnection. if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread) || (c->connectionType == Qt::QueuedConnection)) { queued_activate(sender, signal_index, c, argv ? argv : empty_argv, locker); continue; #ifndef QT_NO_THREAD } else if (c->connectionType == Qt::BlockingQueuedConnection) { if (receiverInSameThread) { qWarning("Qt: Dead lock detected while activating a BlockingQueuedConnection: " "Sender is %s(%p), receiver is %s(%p)", sender->metaObject()->className(), sender, receiver->metaObject()->className(), receiver); } //当信号槽同线程时一定不能用BlockingQueuedConnection,否则可能死锁。 //信号量,之后新建一个元对象调用事件的对象,并post到对应的receiver队列,并且解除掉上面的互斥锁 QSemaphore semaphore; QMetaCallEvent *ev = c->isSlotObject ? new QMetaCallEvent(c->slotObj, sender, signal_index, 0, 0, argv ? argv : empty_argv, &semaphore) : new QMetaCallEvent(c->method_offset, c->method_relative, c->callFunction, sender, signal_index, 0, 0, argv ? argv : empty_argv, &semaphore); QCoreApplication::postEvent(receiver, ev); locker.unlock(); semaphore.acquire(); locker.relock(); continue; #endif } //inline void switchSender(QObject *receiver, QObject //*sender, int signal_absolute_id) //{ // this->receiver = receiver; // currentSender.sender = sender; // currentSender.signal = signal_absolute_id;//绝对信号ID // currentSender.ref = 1; // previousSender = //QObjectPrivate::setCurrentSender(receiver, ¤tSender); // switched = true; //}这个是switchSender调用的源码,就是对修改receiver,previousSender QConnectionSenderSwitcher sw; if (receiverInSameThread) { sw.switchSender(receiver, sender, signal_index); } //看注释 if (c->isSlotObject) { c->slotObj->ref(); QScopedPointer<QtPrivate::QSlotObjectBase, QSlotObjectBaseDeleter> obj(c->slotObj); locker.unlock(); obj->call(receiver, argv ? argv : empty_argv); // Make sure the slot object gets destroyed before the mutex is locked again, as the // destructor of the slot object might also lock a mutex from the signalSlotLock() mutex pool, // and that would deadlock if the pool happens to return the same mutex. obj.reset(); locker.relock(); } else if (c->callFunction && c->method_offset <= receiver->metaObject()->methodOffset()) { //we compare the vtable to make sure we are not in the destructor of the object. 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); //元对象调用 callFunction(receiver, QMetaObject::InvokeMetaMethod, method_relative, argv ? argv : empty_argv); //确认槽结束回调,先写到这里。 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); } metacall(receiver, QMetaObject::InvokeMetaMethod, methodQScopedPointer, argv ? argv : empty_argv); 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); if (connectionLists->orphaned) break; } while (list != &connectionLists->allsignals && //start over for all signals; ((list = &connectionLists->allsignals), true)); } if (qt_signal_spy_callback_set.signal_end_callback != 0) qt_signal_spy_callback_set.signal_end_callback(sender, signal_index); }