为什么Qt信号不是常数

时间:2016-09-01 22:21:13

标签: c++ qt signals-slots

Qt使用signals and slots进行对象通信。 Signals 通常被声明为成员函数,然后Qt MOC生成该函数的定义。

我想了解的是为什么信号不是const成员函数?

编辑: 我希望信号不会修改发件人,这就是问题的原因。

3 个答案:

答案 0 :(得分:9)

  

我希望信号不会修改发件人

信号(如generated by the MOC)不直接修改类实例'成员。但是,生成的代码会传递this指针,供(潜在)插槽使用。因此,连接的插槽可能会改变信号的发送方。

因此,技术原因是,如果信号为const,则需要所有插槽实现只调用发送方上的const类成员,以便编译代码而不会出错。

在代码安全方面,将信号实现为非const类成员是一个可以理解的决定。在许多情况下,它仍然感觉不自然(例如,如果在同一类中实现的连接槽是const,或者连接的槽完全属于另一个对象。)

答案 1 :(得分:5)

没有什么可以阻止Qt信号为const AFAIK (使用Qt5.9测试)。 IInspectable 的答案不正确。

以下是我做的测试,表明仍有可能 - 在同一实例中将 const信号连接到非常量插槽 - 在sender()上调用非常量方法

我的测试类,编译精细(gcc):

// Stupid class to test the emit of a const-signal
class Test : public QObject
{
    Q_OBJECT

public:
    // Connect in the constructor from this instance to this instance
    explicit Test(QObject *parent = nullptr) : QObject(parent) {
        connect(this, &Test::valueChanged, this, &Test::updateString);
    }

    // To test a non-const method call
    void nonConstFoo() {
        setObjectName("foo"); // I modify the 'this' instance
    }

    // To test emit of a non-const signal from a const-method
//    void constFoo() const {
//        emit fooSignal(); // --> FAIL at compile time
//    }

public slots:
    void setValue(int value) {
        m_value = value;
        emit valueChanged(value);
    }

    void updateString(int value) {
        m_string = QString::number(value); // I modify the 'this' instance
        nonConstFoo(); // I modify the 'this' instance through a non-const call

        auto s = sender();
        s->setObjectName("mutated name"); // I modify the 'sender' instance

        qDebug() << "Updated string" << m_string;
    }

signals:
    void valueChanged(int) const; // The signal is const
    void fooSignal(); // Non-const signal

private:
    int m_value;
    QString m_string;
};

以下是MOC为信号生成的代码:

// SIGNAL 0
void Test::valueChanged(int _t1)const
{
    void *_a[] = { nullptr, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };
    QMetaObject::activate(const_cast< Test *>(this), &staticMetaObject, 0, _a);
}

// SIGNAL 1
void Test::fooSignal()
{
    QMetaObject::activate(this, &staticMetaObject, 1, nullptr);
}

我们可以看到Qt在 this 上使用了 const_cast ,所以一切都会正常工作。

在我看来,默认情况下信号不是常数的原因是,这需要MOC在中添加一个const到你的信号(== class-method)定义标题,因此修改您的源代码。

我想这可以通过将每个信号定义包含在宏中来实现,但想象一下编码器和读者的痛苦。我没有看到Qt(你也没有)将你的信号声明为const的任何好处,这对你和Qt来说需要更多的工作。

但是有时您可能需要将它们声明为const。就像你想从const方法发出它们一样。你可以自由地这样做。

答案 2 :(得分:0)

信号可以是const,实际上,如果要从const函数发出信号,则它必须是const信号,但是在插槽端,则不必是const。当用const pures重新实现抽象类时,我不必使用这种可变方法。