为什么Qt信号不是常数

Mac*_*Mac 9 c++ qt signals-slots

Qt使用信号和插槽进行对象通信.信号通常被声明为成员函数,然后Qt MOC生成该函数的定义.

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

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

IIn*_*ble 10

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

信号(由MOC生成)不直接修改类实例的成员.然而,生成的代码传递this指针,以供(潜在)时隙消耗.因此,连接的插槽可以改变信号的发送方.

因此技术原因是,如果信号是const,则需要所有插槽实现仅调用const发送方上的类成员以使代码编译而没有错误.

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

  • “这将要求所有插槽实现也必须是 const”——不,这意味着接收指向发送者对象的指针的参数将是 `const` 限定的,而不是隐式的 `this` 参数.. (3认同)

ymo*_*eau 6

没有什么可以阻止Qt信号成为AFAIK常量(已通过Qt5.9测试)。IInspectable的答案不正确。

下面是一个测试,我做表明它仍然是可能的
-一个连接常量信号非const槽在同一个实例
-调用非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;
};
Run Code Online (Sandbox Code Playgroud)

这是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);
}
Run Code Online (Sandbox Code Playgroud)

我们可以看到Qt 对此使用了const_cast,因此一切都会正常进行。


在我看来,这些信号是不是常量默认的原因是,这将需要建设部一个const添加到您的信号(==类方法)定义你的头,因此修改源代码。

我想这可以通过将每个信号定义放在一个宏中来实现,但是可以想象一下编码人员和读者的痛苦。我看不到Qt(也不是您)将信号声明为const的任何收益(这对您和Qt都需要更多的工作)。

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

  • 使用 `const_cast` 丢弃 `const` 限定符很好。在丢弃限定符后通过指向 `const` 的指针/引用来改变对象是未定义的行为。看起来在工作是一种完全有效的未定义行为形式。它仍然是未定义的,并且一致的实现使得 **no** 保证结果或整个程序。 (2认同)