先說一下問題,我們在定義信號或槽的時候為什么會定義成返回值為void ?,信號或槽能否有返回值?如果有返回值,那么什么情況下可以有返回值? 信號或槽定義成返回值為void類型或其它返回值那種好些呢?參數和返回值如何處理呢?
信號&槽的調用分為同步調用和異步調用,同步過程大致如下圖:
CTestMoc由于使用了信號和槽,所以在編譯時會生成一個Moc文件,在Moc文件里可以看到所謂的信號其實是一個函數,而通過信號調用槽的過程就是從這里發起。下面根據調用的步驟來分析下調用過程。
1 void CTestMoc::Test1()
信號函數,信號調用槽整個過程從這里發起。
2 QMetaObject::activate
這個函數是QMetaObject類的靜態函數,它有4個入參
QObject *sender 發射信號對象
const QMetaObject *m 發射信號對象的元對象
int local_signal_index 信號相對索引
void **argv 入參和返回值
CTestMoc::Test1調用此函數帶么為
QMetaObject::activate(this, &staticMetaObject, 0, 0)
可以看到
Sender-----this
m----- staticMetaObject
local_signal_index ----- 0(此信號相對索引為0)
argv ---- 0 (沒有入參且返回值為void類型)
3 QMetaObject::activate
第三步是一個重載函數,與第二步函數名相同,但入參有很大區別,它通過第二步入參,發送信號的元對象獲取信號的絕對偏移量,這樣就能在QObjectPrivate對象中獲取保存信號和槽連接關系的list
QObject *sender-----信號發射對象
int signalOffset------信號絕對偏移量
int local_signal_index-----信號相對索引
void **argv-----參數和返回值
此函數主要偽代碼分析如下:
void QMetaObject::activate(……)
{
計算絕對索引
獲取QObjectPrivate的connectionLists(信號&槽連接connect鏈表)引用
根據絕對索引在vector中獲取對應的connectlist
Do
{
保存鏈表開始和結束位置
Do
{
判斷連接類型
If (同一個線程)
直接調用
Else
拷貝參數,創建QEvent加入事件循環
}
While(鏈表是否結束)
}
While( 判斷list是否結束)
}
4 直接調用
判斷是否在同一個線程,如果是則直接調用在moc文件中初始化QMetaObject對象注冊的qt_static_metacall函數,調用此函數參數是根據鏈表中保存的QObjectPrivate::Connection對象,在connection對象中保存了接受信號對象的槽函數索引、對象等信息。
5 槽調用
調用qt_static_metacall函數會給出對應的槽函數索引調用對應的槽函數。
Ok,信號&槽直接調用過程大致說清楚了,那么定義帶有返回值的信號會怎么樣呢?下次接著分析!