Почему этот пример Qt работает с адресами, а не с самими объектами и функциями? И нет ключевых слов SLOT/SIGNAL?

Я столкнулся с этим кодом в документации Qt:

Counter a, b;

QObject::connect(&a, &Counter::valueChanged,

                 &b, &Counter::setValue);

a.setValue(12);     // a.value() == 12, b.value() == 12
b.setValue(48);     // a.value() == 12, b.value() == 48

Почему перед a и b и перед функциями стоит &? a — излучающий объект (предоставляет сигнал), а b — принимающий объект (имеет слот), так почему же здесь берется их адрес, а не просто используются сами объекты (и берется адрес объекта, если я не ошибся)? В других примерах Qt это не так (адрес не используется, используются сами объекты)

Я не слишком уверен, как работают & перед вызовами функций (т.е. Counter::valueChanged и Counter::setValue)... Я думаю, что это заставляет их возвращаться по ссылке, но я не уверен, насколько это важно здесь.

Наконец, почему нет ключевых слов SLOT и SIGNAL? Разве это не должно быть SIGNAL(Counter::valueChanged) и SLOT(Counter::setValue)? Опять же, это то, что я видел в других примерах QObject:connect, и этот пример не имеет для меня смысла.

Любая помощь приветствуется!


person James Ronald    schedule 10.06.2019    source источник
comment
QObject::connect ожидает указатели.   -  person drescherjm    schedule 10.06.2019
comment
См. документацию Qt относительно другой реализации QObject::connect   -  person Dimitry Ernot    schedule 10.06.2019
comment
Это новый (Qt5) типобезопасный способ подключения, см. документы, на которые ссылается Romha.   -  person Frank Osterfeld    schedule 10.06.2019


Ответы (1)


Посмотри на это:

Counter a, b; // objects created on the stack, they are not pointers

// get the addresses of the objects and assign them as pointers.
Counter *aPointer = &a;
Counter *bPointer = &b;

Следующее не будет компилироваться, потому что a и b не являются указателями, а QObject connect ожидает указатели на экземпляры классов, наследуемых от QObject.

QObject::connect(a, &Counter::valueChanged, b, &Counter::setValue);

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

QObject::connect(aPointer, &Counter::valueChanged, bPointer, &Counter::setValue);

Точно так же это также работает, потому что вы берете адрес (он же указатель) объектов:

QObject::connect(&a, &Counter::valueChanged, &b, &Counter::setValue);

Надеюсь, это объясняет & перед объектами. Затем есть &'s перед именами функций. Это синтаксис указателя на функцию-член:

&Counter::valueChanged 

Имя класса (Counter), дополненное ::, и имя функции-члена (valueChanged), предваряемое знаком &.

В данном случае это член указателя, который предоставляется в качестве первого аргумента. Это называется сигнал. Под капотом Qt вызывает их вместе.

QObject *sender = &a;
std::function<void()> signal = std::bind(&Counter::valueChanged,sender);
...
signal(); // the function is called here

То же самое происходит и со слотом.

Наконец, используются макросы SIGNAL() и SLOT() ‹ Qt 5.0. Поэтому он устарел и больше не должен использоваться. В некоторых редких случаях вы все равно должны использовать его, поскольку нет другой альтернативы, например. с QtDBus, но это уже другая тема.

Я надеюсь, что это проясняет некоторые из ваших вопросов.

person fonZ    schedule 10.06.2019
comment
Большое спасибо! Только одно: я думаю, вы сделали тип и хотели сказать ‹ Qt 5.10.0? Потому что у меня Qt 5.9.8, но моя кодовая база все еще активно использует SLOT() и SIGNAL()... или, может быть, мы просто делаем это неправильно? Тем не менее, спасибо! - person James Ronald; 11.06.2019
comment
@JamesRonald Пожалуйста. И я имел в виду ‹ Qt5, а не 5.10.0. Макросы SIGNAL/SLOT устарели, то есть они все еще доступны для обратной совместимости, но их больше нельзя использовать. Так что, если ваша кодовая база все еще содержит их, это нормально, потому что она все еще работает, но вам следует подумать об изменении ее на новый синтаксис, так как рано или поздно он будет удален и вызовет проблемы с обновлением. И еще одна причина изменить его заключается в том, что SIGNAL/SLOTS выдают ошибки времени выполнения, а не времени компиляции, что делает все это более подверженным ошибкам. - person fonZ; 11.06.2019