调用是否有效
QObject::connect(a, SIGNAL(somesig(someparam)), b, SLOT(someslot()));
没有参数?它似乎有效(没有抛出运行时异常),但我在文档中找不到参考。我所发现的是,如果 someslot 有一个默认参数,这是可能的。在这种情况下是有效的。但是我的方法 someslot 的参数集与默认值不同(示例中没有参数)。
那么似乎可以将信号连接到参数较少的插槽?
是的,没关系。Signals & Slots文档中有一段简短的描述:
[...] 信号的签名必须与接收时隙的签名相匹配。(事实上,一个插槽的签名可能比它接收到的信号更短,因为它可以忽略额外的参数。) [...]
在解释默认参数的页面下方甚至还有一个类似的示例。
就标准 C++ 而言,Qt 解决方案也很有效。
发出信号是通过调用方法完成的:
emit someSignal(3.14);
emit
关键字实际上解析为空#define
,所以上面的行只是用给定的参数调用方法someSignal
。该方法可能已在QObject
派生类中声明,如下所示:
class SomeObject: public QObject {
Q_OBJECT
public slots:
void firstSlot() { /* implementation */ }
void secondSlot(double) { /* implementation */ }
signals:
void someSignal(double); /* no implementation here */
};
这对您来说应该很熟悉,但您可能想知道信号的实际实现来自哪里。正如您可能猜到的那样,这就是 Qt 的元对象编译器 (MOC) 发挥作用的地方。对于在该部分中声明signals
的每个方法,它在其生成的源代码中提供一个大致如下所示的实现:
void SomeObject::someSignal(double _t1)
{
void *_a[] = { Q_NULLPTR, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
QMetaObject::activate(this, &staticMetaObject, 1, _a);
}
有趣的部分是void *_a[]
填充了指向传递给信号的参数的指针的向量。这里没有什么特别的。
参数向量被传递给QMetaObject::activate
,它依次进行一些线程安全检查和其他内务处理,然后开始调用已连接到信号的槽(如果有)。由于信号到插槽的连接是在运行时解决的(connect()
工作方式),所以再次需要 MOC 的一点帮助。特别是,MOC 还会为qt_static_metacall()
您的类生成一个实现:
void SomeObject::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
SomeObject *_t = static_cast<SomeObject *>(_o);
Q_UNUSED(_t)
switch (_id) {
case 0: _t->firstSlot(); break;
case 1: _t->secondSlot((*reinterpret_cast< double(*)>(_a[1]))); break;
default: ;
}
} /* some more magic */
}
如您所见,此方法包含将void *_a[]
向量从之前解析为函数调用的另一端。您还可以看到没有可变参数列表(使用省略号,...
)或其他有问题的诡计。
So to enlighten the original question: When, e.g. someSignal(double)
is connected to the secondSlot(double)
that matches the signal's signature, the call resolves to case 1
in the qt_static_metacall
and it just passes the argument as expected.
When connecting the signal to the firstSlot()
that has fewer arguments than the signal, the call resolves to case 0
and firstSlot()
gets called without arguments. The argument that has been passed to the signal simply stays untouched in its void *_a[]
vector.