Безопасно ли подключать сигнал к чисто виртуальному слоту в конструкторе базового класса? - PullRequest
0 голосов
/ 28 ноября 2018

Я спрашиваю себя, является ли следующий код безопасным:

#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 нет вызова виртуального метода, то я пока не вижу побочных эффектов, ноэто правда?

Спасибо.

1 Ответ

0 голосов
/ 29 ноября 2018

Нет проблем, потому что вызов слота не дается в конструкторе или деструкторе класса, а вызывается циклом событий, что можно наблюдать в .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);
# ...
...