日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Qt / Moc 和信号 - 槽解析

發布時間:2024/10/14 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Qt / Moc 和信号 - 槽解析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

一. MOC

二. moc_test.cpp 分析

三. connect

四. activate

五. 總結


版本 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.)" #endifQT_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];//保存類中被 QT 宏修飾過的函數名稱。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_LITERALstatic const uint qt_meta_data_test[] = {//保存了信號,槽及 moc 識別的其他函數的個數,函數索引,返回類型,參數個數,參數類型等信息。// content:8, // revision0, // classname0, 0, // classinfo8, 14, // methods0, 0, // properties0, 0, // enums/sets0, 0, // constructors0, // flags4, // signalCount// signals: name, argc, parameters, tag, flags1, 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, flags7, 0, 60, 2, 0x0a /* Public */,8, 0, 61, 2, 0x0a /* Public */,9, 1, 62, 2, 0x0a /* Public */,// methods: name, argc, parameters, tag, flags11, 0, 65, 2, 0x02 /* Public */,// signals: parametersQMetaType::Void,QMetaType::Void,QMetaType::Void,QMetaType::Void, QMetaType::Int, 6,// slots: parametersQMetaType::Void,QMetaType::Void,QMetaType::Void, QMetaType::Int, 10,// methods: parametersQMetaType::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 *>(std::addressof(_t1)))};QMetaObject::activate(this, &staticMetaObject, 3, _a); }

test.h 中構造函數一個,普通函數一個(getValue),signal 4 個,slot 3 個,Q_INVOKABLE 修飾的方法一個。其中 3 個槽函數需要自己在 test.cpp 里實現,4個信號函數由 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 = {{QMetaObject::SuperData::link<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::connectQMetaObject::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::addConnectionQObjectPrivate::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 ConnectionListConnection *nextConnectionList;//senders linked listConnection *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 inUsebool dirty; //some Connection have been disconnected (their receiver is 0) but not removed from the list yetint inUse; //number of functions that are currently accessing this object or its connectionsQObjectPrivate::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_metacallcallFunction(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_metacallmetacall(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 dataconst 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);elsereturn 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,調用槽函數。

    ?

    轉載于:https://blog.csdn.net/z_QaQ/article/details/105382418

    ?

    (SAW:Game Over!)

    總結

    以上是生活随笔為你收集整理的Qt / Moc 和信号 - 槽解析的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 69国产| 国产综合精品视频 | 成人av电影在线播放 | 久久久久久久久久久久电影 | 91精品系列| 日韩激情视频 | 亚洲大色网| 成人免费性生活视频 | 免费福利影院 | 欧美精品v国产精品v日韩精品 | 国产精品久久久一区 | 久久久久久在线观看 | 一本色道久久综合亚洲二区三区 | 日韩一级免费 | 亚洲做受高潮无遮挡 | 国产又粗又猛又大爽 | 国产综合一区二区 | 天天操免费视频 | 日本高清视频www | 日韩成人av一区二区 | 另类小说欧美 | 天堂av官网 | 国产精品无码一区二区三区免费 | 美女张开腿让男人操 | 国产色视频 | 欧美日韩激情在线一区二区三区 | 久久久久久久黄色 | 操视频网站| 欧美熟妇激情一区二区三区 | 成人午夜一区二区 | 久久黄色影视 | 国产在线网站 | 久久成人av | 伊人开心网 | 日韩精品视频久久 | 日本在线视频一区 | 亚洲精品高清在线观看 | a一级免费视频 | 日韩av线 | 四虎1515hh.com| 在线成人日韩 | 亚洲av无码一区二区三区四区 | 国产a级精品 | 青青青草视频在线 | 琪琪色在线视频 | 精品久久久亚洲 | 亚洲h网站 | 免费看的黄色录像 | 99久久婷婷国产综合精品青牛牛 | 亚洲自拍偷拍网 | 亚洲一区二区三区免费观看 | 青青国产 | 国产主播一区 | 97国产在线播放 | 99久久久无码国产精品性青椒 | 97视频在线 | 男男play呻吟动漫网站 | 九色porny原创自拍 | 国产jk精品白丝av在线观看 | 性生交大片免费看视频 | 国产xxxx孕妇| 中文字幕一区二区三区又粗 | 日韩精品成人无码专区免费 | 亚洲精品乱码久久久久久写真 | 日本精品一区二区在线观看 | 久久影院一区二区 | 嫩草视频在线播放 | 亚洲精品一区二区18漫画 | 国产黄色www | 九色国产| 国产91精品在线观看 | 久久久久久久美女 | 麻豆乱码国产一区二区三区 | 亚洲人成在线免费观看 | 爱爱一区 | 日韩久久久久 | 欧美极品少妇 | 亚洲最大免费视频 | 大奶骚| 可以免费看的av | 免费成人av在线播放 | 天堂在线中文8 | 玉米地疯狂的吸允她的奶视频 | 日韩福利视频导航 | 久久久久国产一区二区三区 | 黄色三级小视频 | 欧美三p| 天天爽夜夜 | 污视频网站免费在线观看 | 成人午夜网 | 成年网站在线播放 | 偷自拍 | av一卡二卡| 中国一级片在线观看 | 欧美日韩国产在线观看 | 欧美性日韩 | 日韩中出在线 | 日韩av区 | 狠狠亚洲|