【问题标题】:Is it safe to connect a signal to a pure virtual slot in a constructor of a base class?将信号连接到基类的构造函数中的纯虚拟槽是否安全?
【发布时间】:2018-11-28 20:55:44
【问题描述】:

我问自己以下代码是否安全:

#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 类构造函数中没有调用虚方法,那么到目前为止我没有看到任何副作用,但这是真的吗?

谢谢。

【问题讨论】:

  • 这应该没问题,只要您坚持使用“旧式”连接语法(使用SIGNALSLOT)。使用函数指针的 Qt5 版本将无法使用。
  • 您能否解释一下为什么它在新的连接语法中“不起作用”?因为@eyllanesc 的回答建议使用它。
  • 我记得不久前尝试这样做时遇到了编译器错误。但是使用我当前的编译器确实可以工作。所以是的,@eyllanesc 的回答是正确的。只要您的编译器接受在构造函数中使用纯虚拟成员,它就可以工作 - 因此您应该确实使用新语法。

标签: c++ qt qt5 qt-slot


【解决方案1】:

没有问题,因为对slot的调用不是在类的构造函数或析构函数中给出的,而是由事件循环调用的,可以在.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);
# ...

【讨论】:

  • 您的答案是正确的,但您应该暗示这仅适用,只要信号本身不是从构造函数发出的。调用connect(...); emit signal1(); 会因为“调用纯虚方法”异常而终止应用程序
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-21
  • 2019-04-20
  • 2012-01-27
  • 1970-01-01
相关资源
最近更新 更多