Використання emit vs виклику сигналу так, ніби це звичайна функція в Qt


97

Скажімо, я маю такий сигнал:

signals:
    void progressNotification(int progress);

Я нещодавно дізнався про ключове слово emit у Qt. До цього часу я виконував сигнали, просто викликаючи їх як звичайну функцію. Отже, замість:

emit progressNotification(1000 * seconds);

Я б написав:

progressNotification(1000 * seconds);

Викликати їх так здавалося, працювало, і всі підключені слоти виконувались, тож використання ключового слова emit спричиняє іншу поведінку, чи це просто синтаксичний цукор?


17
+1 Ніколи не знав, що emitце не потрібно. Однак дивно, що ви дізналися про це emitдовго після безпосереднього виклику сигналів, оскільки система слот-сигналів є однією з перших речей, які слід дізнатися про Qt.
Крістіан Рау,

Відповіді:


88

emitце просто синтаксичний цукор. Якщо ви подивитесь на попередньо оброблений вихід функції, яка випромінює сигнал, ви побачите, що emitїї просто немає.

"Чарівність" відбувається в сформованому коді для функції випромінювання сигналу, на який ви можете подивитися, перевіривши код C ++, згенерований moc.

Наприклад, fooсигнал без параметрів генерує цю функцію-член:

void W::foo()
{
    QMetaObject::activate(this, &staticMetaObject, 0, 0);
}

І код emit foo();попередньо обробляється простоfoo();

emitвизначається в Qt/qobjectdefs.h(у будь-якому випадку у відкритому джерелі джерела), наприклад:

#ifndef QT_NO_EMIT
# define emit
#endif

( no_keywordsЗахисник дефініції - дозволити вам використовувати Qt з іншими фреймворками, що мають імена, що стикаються, за допомогою опції налаштування QMake.)


14
Чи знаєте ви, чи було коли-небудь реалізація (або запланована реалізація) того, emitщо насправді робило більше, ніж нічого? Я вважаю, що наявність "синтаксичного цукру" в цьому випадку просто бентежить новачка (або принаймні мене, коли я був початківцем користувачем Qt) - здається, що щось магічне або важливе відбувається з emitпсевдо-ключовим словом, коли воно нічого не робить все - вся магія відбувається в звичайній старій функції, яка mocстворює ( mocце магія для сигналів і слотів Qt). emitце непотрібне прикраса, яке не робить нічого, крім того, що здається важливим.
Michael Burr,

12
Виділення - це не "просто прикраса". emitповідомляє людині, яка читає дзвінок, що магія скоро відбудеться (тобто це буде запускати код в об’єктах, про які цей клас потенційно ніколи не чув, і ці виклики можуть бути синхронними або асинхронними), що по суті повністю втрачається, якщо пропустити ключове слово. Використай це. Це автоматичне документування. "Новачки" повинні читати документи та навчальні посібники, і emitвони завжди там (в офіційному документі все одно). Відкриття того, що ви можете просто викликати функцію, має відбутися після того, як ви «побачили світло» - ви вже не новачок на той момент.
Mat

19
Хм, я не впевнений, що погоджуюся з вами щодо того, наскільки цінним є emit"ключове слово". Думаю, я би віддав перевагу використанню правила іменування, якщо потрібно чітко пояснити, що виклик функції є сигналом.
Michael Burr

2
Ну, я кардинально не погоджуюся з цим :) Примушування конвенції про іменування - це те, що ви можете зробити самі у своїх проектах / на робочому місці, Qt не заважає цьому. Qt не змушує вас використовувати "ключове слово" і навіть дозволяє вимкнути його, якщо воно зіткнеться з іншими частинами вашого коду. На мою думку, підхід до ключових слів кращий - компілятор не може допомогти вам застосовувати політику іменування, але він виявить неправильну орфографію emit.
Mat

15
Щоб бути зрозумілим - я не виступав за використання конвенції іменування - просто, якщо причиною emitpsuedo-keyword-comment було чітке пояснення того, що сигнал викликається, то конвенція іменування може зробити те саме, без таємничості та зі схожими перевагами. Конвенція іменування не може бути застосована Qt (насправді, mocможе її застосувати - але я не виступаю за це), але Qt не може забезпечити використання emitжодної. І хоча ви можете "вимкнути", emitякщо виникне суперечка імен, це не надто допомагає, якщо у вас є купа вихідних файлів, які його використовують (без потреби, для завантаження).
Michael Burr

2

Через 18 місяців ... Я почав із коментарів під відповіддю @ Mat, і швидко закінчився номер. Таким чином відповідь.

ІМО emitне є ні синтаксичним цукром, ні простим ключовим словом у тому сенсі

  1. Він генерує код (як пояснив @Mat вище),
  2. Це допомагає connectмеханізму визнати, що насправді це є signal, і
  3. Це робить ваш сигнал частиною "більшої" системи, де сигнали та відповіді (слоти) можуть виконуватися синхронно або асинхронно, або в черзі, залежно від того, де і як сигнал випромінювався. Це надзвичайно корисна функція системи сигнал / слот.

Вся система сигнал / слот - це інша ідіома, ніж простий виклик функції. Я вважаю, що це випливає із моделі спостерігачів. Також існує велика різниця між a signalі a slot: сигнал не повинен бути реалізований, тоді як слот повинен бути !

Ви йдете вулицею і бачите палаючий будинок (сигнал). Ви набираєте номер 911 ( підключіть сигнал пожежі до гнізда відповіді 911 ). Сигнал був лише випущений , тоді як слот був реалізований пожежною службою. Можливо, це неточно, але ви зрозуміли ідею. Давайте розглянемо приклад OP.

Деякий серверний об'єкт знає, наскільки успішно досягнуто. Тож це могло просто emit progressNotification(...)сигналізувати. Клас, який відображає фактичну індикацію прогресу, повинен взяти цей сигнал і виконати на ньому. Але як подання підключається до цього сигналу? Ласкаво просимо до системи сигналів / слотів Qt. Тепер можна уявити клас менеджера (як правило, віджет сортів), який складається з об’єкта подання та об’єкта обчислення даних (обидва вони QObjectsможуть бути ) connect (m_myDataEngine, &DataEngine::progressNotification, m_myViewObj, &SimpleView::displayProgress).

Не будемо вдаватися до аспектів дизайну класу менеджера, але достатньо сказати, що саме тут світить система сигналів / слотів. Я можу зосередитись на розробці дуже чистої архітектури для мого додатка. Не завжди, але часто буває, я виявляю, що я просто видаю сигнали, але реалізую слоти .

Якщо можливо використовувати / викликати метод сигналу, ніколи його не видаючи , то це обов'язково означає, що вам ніколи не була потрібна ця функція як сигнал .


6
Ні, emitнасправді є лише порожнім макросом і суто необов’язковим. Не так це ключові слова signalі slotякі обробляє moc. signalвикористовується для забезпечення реалізації функції, slotвикористовується для створення запису мета-об'єкта, щоб він знаходився з SLOT(MySlot())макросом або в QML. emitє синтаксичним цукром. Ніщо ніколи не поскаржиться, якщо ви пишете emit i++;(але, можливо, ваші колеги), і ви все одно не можете зв’язатися i++.
derM

-5

Другий варіант означав би, що ви завжди знаєте, що таке ім'я функції та параметри функції, і що об'єкт, до якого ви його надсилаєте, відомий саме цією функцією. Ці два випадки не завжди відповідають дійсності, тому це дві основні речі, чому були створені слоти та сигнали. "під капотом" механізм сигналу і слота - це просто таблиця з покажчиками на кожну функцію, яка підключена.

Крім того, подивіться на цей pdf, який дуже чітко пояснює природу механізму сигналів і слотів: http://www.elpauer.org/stuff/a_deeper_look_at_signals_and_slots.pdf


В обох напрямках потрібно знати назву сигналу та його параметри - ви його випромінюєте, як ви могли випускати те, чого не знаєте? Обидва мають однакову семантику, вони ідентичні.
мат

1
Можливо, ви зіпсуєте сигнальний дзвінок із прямим слот-дзвінком? Але мушу визнати, що спочатку я також задавався питанням щодо назви запитання, оскільки ніколи не знав, що emitце просто заборона. Але навіть у цьому випадку читання запитувального органу мало б прояснити ситуацію, тому -1.
Крістіан Рау,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.