14

调用是否有效

QObject::connect(a, SIGNAL(somesig(someparam)), b, SLOT(someslot()));

没有参数?它似乎有效(没有抛出运行时异常),但我在文档中找不到参考。我所发现的是,如果 someslot 有一个默认参数,这是可能的。在这种情况下是有效的。但是我的方法 someslot 的参数集与默认值不同(示例中没有参数)。

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

4

2 回答 2

22

是的,没关系。Signals & Slots文档中有一段简短的描述:

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

在解释默认参数的页面下方甚至还有一个类似的示例。

于 2013-08-22T18:53:38.273 回答
3

就标准 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.

于 2017-02-12T14:58:41.217 回答