先说一下问题,我们在定义信号或槽的时候为什么会定义成返回值为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,信号&槽直接调用过程大致说清楚了,那么定义带有返回值的信号会怎么样呢?下次接着分析!