Qt使用信号和槽机制进行对象通信。通常将信号声明为成员函数,然后由Qt MOC生成该函数的定义。
我想了解的是为什么信号不是const成员函数?
编辑: 我期望信号不会修改发送者,这就是我的问题所在。
Qt使用信号和槽机制进行对象通信。通常将信号声明为成员函数,然后由Qt MOC生成该函数的定义。
我想了解的是为什么信号不是const成员函数?
编辑: 我期望信号不会修改发送者,这就是我的问题所在。
我希望信号不会修改发送者
信号(如MOC生成的)不直接修改类实例的成员。然而,生成的代码会传递一个this
指针,以供(可能的)槽函数使用。连接的槽函数因此可以改变信号的发送者。
所以技术上的原因是,如果信号是const
的,那么所有的槽函数实现都必须只调用发送者的const
类成员,才能使代码编译通过而没有错误。
将信号实现为非const
类成员是一个可以理解的决定,考虑到代码安全性。但在某些情况下仍然感觉不自然(例如,如果连接的槽函数在同一类中实现为const
,或者连接的槽函数属于完全不同的对象)。
const QObject obj;
所以这是无关紧要的。使用const信号的唯一缺点是在sender()
上失去const正确性,这通常甚至都不被使用。即使在使用时,调用非const函数也不是无效的,只是很糟糕的做法而已。 - Joseph Ireland据我所知,没有任何东西阻止Qt信号成为const(在Qt5.9中测试过)。IInspectable的答案是不正确的。
下面是我进行的测试,以表明仍然可以:
- 将const信号连接到同一实例中的非const槽
- 在sender()
上调用非const方法。
我的测试类编译良好(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);
}
const_cast
移除 const
限定符是可以的。但是在移除限定符后通过指向 const
的指针/引用修改对象是未定义行为。看起来正常运作只是未定义行为的一种形式。它仍然是未定义的,符合规范的实现不会对结果或整个程序的完整性做任何保证。 - IInspectableconst_cast
是由MOC生成的,然后QMetaObject::activate
明显使用该指针调用非const方法,例如:sender->d_func()
。我假设Qt开发人员在生成此const_cast
时知道他们在做什么,对吗? - ymoreauconst_cast
并不是100%安全的,但是当您使用Qt时,您知道在QObject上这样做是极不鼓励的。 - ymoreau信号可以是const的,实际上如果你想从一个const函数中发出信号,那么这个信号必须是const的,但在槽函数中它不需要是const的。当使用const pures重新实现抽象类时,我通过这种方式避免了使用可变对象。