在Qt中允许将信号连接到具有较少参数的插槽?

时间:2013-08-22 18:33:56

标签: qt signals slot

调用

是否有效
QObject::connect(a, SIGNAL(somesig(someparam)), b, SLOT(someslot()));
没有参数?它似乎工作(没有抛出运行时异常),但我在文档中找不到引用。我发现只有someslot有一个默认参数才有可能。在这种情况下它是有效的。但是我的方法someslot没有与默认值相同的参数集(示例中没有参数)。

所以似乎可以将信号连接到参数较少的插槽?

2 个答案:

答案 0 :(得分:14)

是的,没关系。在Signals & Slots文档中有一个简短的句子:

  

[...]信号的签名必须与接收槽的签名相匹配。 (事实上,一个插槽的签名可能比它收到的信号更短,因为它可以忽略额外的参数。)[...]

甚至还有一个例子就是在页面的下方解释默认参数。

答案 1 :(得分:1)

就标准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[]向量从之前解析为函数调用。您还可以看到没有可变参数列表(使用省略号,...)或其他可疑的诡计。

因此,要启发原始问题:何时,例如someSignal(double)已连接到与信号签名匹配的secondSlot(double),调用将解析为case 1中的qt_static_metacall,并且只是按预期传递参数。

当信号连接到参数少于信号的firstSlot()时,调用解析为case 0并且firstSlot()在没有参数的情况下被调用。传递给信号的参数在其void *_a[]向量中保持不变。