在基础 class 的构造函数中将信号连接到纯虚拟插槽是否安全?
Is it safe to connect a signal to a pure virtual slot in a constructor of a base class?
我问自己下面的代码是否安全:
#include <QCoreApplication>
#include <QObject>
#include <QDebug>
#include <QTimer>
class Base : public QObject
{
Q_OBJECT
public:
Base()
{
// is it safe to do that ?
connect(this, SIGNAL(signal1()), this, SLOT(slot1()));
}
virtual ~Base() {}
signals:
void signal1();
public slots:
virtual void slot1() = 0; // could be only virtual
};
class Derived : public Base
{
Q_OBJECT
public slots:
virtual void slot1()
{
qDebug() << "derived slot";
}
void emitSignal1()
{
emit signal1();
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Derived d;
QTimer::singleShot(0, &d, SLOT(emitSignal1()));
return a.exec();
}
#include "main.moc"
输出符合预期:
derived slot
我没看过 connect
方法在幕后做了什么,但我猜它类似于设置回调函数。
如果 Base
class 构造函数中没有调用虚方法,那么到目前为止我没有看到任何副作用,但这是真的吗?
谢谢。
没有问题,因为在 class 的构造函数或析构函数中没有给出对插槽的调用,而是由事件循环调用,并且可以在 .moc 中观察到:
void Base::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
Base *_t = static_cast<Base *>(_o);
Q_UNUSED(_t)
switch (_id) {
case 0: _t->signal1(); break;
case 1: _t->slot1(); break;
default: ;
}
} else if (_c == QMetaObject::IndexOfMethod) {
int *result = reinterpret_cast<int *>(_a[0]);
{
using _t = void (Base::*)();
if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&Base::signal1)) {
*result = 0;
return;
}
}
}
Q_UNUSED(_a);
}
另一方面,建议使用新的连接语法:
# ...
connect(this, &Base::signal1, this, &Base::slot1);
# ...
QTimer::singleShot(0, &d, &Derived::emitSignal1);
# ...
我问自己下面的代码是否安全:
#include <QCoreApplication>
#include <QObject>
#include <QDebug>
#include <QTimer>
class Base : public QObject
{
Q_OBJECT
public:
Base()
{
// is it safe to do that ?
connect(this, SIGNAL(signal1()), this, SLOT(slot1()));
}
virtual ~Base() {}
signals:
void signal1();
public slots:
virtual void slot1() = 0; // could be only virtual
};
class Derived : public Base
{
Q_OBJECT
public slots:
virtual void slot1()
{
qDebug() << "derived slot";
}
void emitSignal1()
{
emit signal1();
}
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Derived d;
QTimer::singleShot(0, &d, SLOT(emitSignal1()));
return a.exec();
}
#include "main.moc"
输出符合预期:
derived slot
我没看过 connect
方法在幕后做了什么,但我猜它类似于设置回调函数。
如果 Base
class 构造函数中没有调用虚方法,那么到目前为止我没有看到任何副作用,但这是真的吗?
谢谢。
没有问题,因为在 class 的构造函数或析构函数中没有给出对插槽的调用,而是由事件循环调用,并且可以在 .moc 中观察到:
void Base::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
Base *_t = static_cast<Base *>(_o);
Q_UNUSED(_t)
switch (_id) {
case 0: _t->signal1(); break;
case 1: _t->slot1(); break;
default: ;
}
} else if (_c == QMetaObject::IndexOfMethod) {
int *result = reinterpret_cast<int *>(_a[0]);
{
using _t = void (Base::*)();
if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&Base::signal1)) {
*result = 0;
return;
}
}
}
Q_UNUSED(_a);
}
另一方面,建议使用新的连接语法:
# ...
connect(this, &Base::signal1, this, &Base::slot1);
# ...
QTimer::singleShot(0, &d, &Derived::emitSignal1);
# ...