Usare emit vs chiamare un segnale come se fosse una normale funzione in Qt


97

Diciamo che ho questo segnale:

signals:
    void progressNotification(int progress);

Solo di recente ho appreso della parola chiave emit in Qt. Fino ad ora, eseguivo i segnali semplicemente chiamandoli come una normale funzione. Quindi invece di:

emit progressNotification(1000 * seconds);

Vorrei scrivere:

progressNotification(1000 * seconds);

Chiamarli in quel modo sembrava funzionare e tutti gli slot collegati sarebbero stati eseguiti, quindi l'uso della parola chiave emit causa un comportamento diverso, o è solo zucchero sintattico?


17
+1 Mai saputo emitnon è necessario. È strano, però, che tu abbia imparato emitmolto dopo aver chiamato i segnali direttamente, poiché il sistema di slot di segnale è una delle prime cose da imparare su Qt.
Christian Rau

Risposte:


88

emitè solo zucchero sintattico. Se guardi l'output preelaborato della funzione che emette un segnale, vedrai che non emitc'è più.

La "magia" avviene nel codice generato per la funzione di emissione del segnale, che puoi osservare esaminando il codice C ++ generato da moc.

Ad esempio un foosegnale senza parametri genera questa funzione membro:

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

E il codice emit foo();viene pre-elaborato semplicementefoo();

emitè definito in Qt/qobjectdefs.h(nella versione open source del sorgente comunque), in questo modo:

#ifndef QT_NO_EMIT
# define emit
#endif

(La definizione di guardia è quella di consentire di utilizzare Qt con altri framework che hanno nomi in no_keywordsconflitto tramite l' opzione di configurazione QMake.)


14
Sai se c'è mai stata un'implementazione (o un'implementazione pianificata) di un emitche in realtà ha fatto più di niente? Trovo che avere lo 'zucchero sintattico' in questo caso confonda solo il principiante (o almeno me quando ero un utente Qt alle prime armi) - sembra che qualcosa di magico o importante stia accadendo con la emitpseudo-parola chiave, quando non fa nulla a all - tutta la magia avviene in una normale vecchia funzione che moccrea ( mocè la magia per i segnali Qt e gli slot). emitè una decorazione inutile che non fa altro che sembrare importante.
Michael Burr

12
Emit non è "solo decorazione". emitdice alla persona che legge la chiamata che la magia sta per accadere (cioè questo attiverà il codice in oggetti di cui questa classe potenzialmente non ha mai sentito parlare, e queste chiamate potrebbero essere sincrone o asincrone), che è essenzialmente totalmente perso se si omette la parola chiave. Usalo. È auto-documentante. I "novizi" dovrebbero leggere documenti e tutorial, ed emitè sempre lì (nei documenti ufficiali comunque). Scoprire che puoi semplicemente chiamare la funzione dovrebbe accadere dopo che hai "visto la luce" - non sei più un principiante a quel punto.
Mat

19
Hmm, non sono sicuro di essere d'accordo con te sul valore della emit"parola chiave". Penso che avrei preferito che fosse utilizzata una convenzione di denominazione se fosse necessario chiarire che una chiamata di funzione è un segnale.
Michael Burr

2
Beh, non sono assolutamente d'accordo con questo :) Forzare una convenzione di denominazione è qualcosa che puoi fare da solo nei tuoi progetti / posto di lavoro, Qt non lo impedisce. Qt non ti obbliga a utilizzare la "parola chiave" e ti consente persino di disattivarla se si scontra con altre parti del codice. A mio parere, l'approccio basato sulle parole chiave è migliore: il compilatore non può aiutarti a far rispettare le politiche di denominazione, ma rileverà un errore di ortografia emit.
Sabato

15
Per essere chiari, non stavo sostenendo che venisse utilizzata una convenzione di denominazione, ma solo che se il motivo di un emitcommento-parola chiave psuedo era di chiarire che viene invocato un segnale, una convenzione di denominazione potrebbe fare lo stesso, senza mistero e con vantaggi simili. La convenzione di denominazione non può essere applicata da Qt (in realtà, mocpotrebbe imporla, ma non sto sostenendo nemmeno quella), ma Qt non può imporre l'uso di emitnessuno dei due. E mentre puoi "disattivare" emitse c'è un conflitto di nomi, ciò non aiuta molto se hai un sacco di file sorgente che lo stanno usando (inutilmente, per l'avvio).
Michael Burr

2

Dopo 18 mesi ... ho iniziato con i commenti sotto la risposta di @ Mat, e stavo finendo rapidamente lo spazio. Così la risposta.

IMO emitnon è né zucchero sintattico né una semplice parola chiave nel senso che

  1. Genera codice (come spiegato da @Mat sopra),
  2. Aiuta il connectmeccanismo a riconoscere che effettivamente è un signal, e
  3. Rende il tuo segnale parte di un sistema "più grande", dove segnali e risposte (slot) possono essere eseguiti in modo sincrono o asincrono, o accodati, a seconda di dove e come il segnale è stato emesso. Questa è una caratteristica estremamente utile del sistema segnale / slot.

L'intero sistema segnale / slot è un linguaggio diverso da una semplice chiamata di funzione. Credo che derivi dal modello dell'osservatore. C'è anche una grande differenza tra a signale a slot: un segnale non deve essere implementato, mentre deve esserlo uno slot !

Stai camminando per strada e vedi una casa in fiamme (un segnale). Componi il 911 ( collega il segnale di fuoco con lo slot di risposta 911 ). Il segnale è stato solo emesso , mentre lo slot è stato realizzato dai vigili del fuoco. Può essere impreciso, ma hai un'idea. Diamo un'occhiata all'esempio di OP.

Alcuni oggetti di backend sanno quanti progressi sono stati fatti. Quindi potrebbe semplicemente emit progressNotification(...)segnalare. Spetta alla classe che visualizza la barra di avanzamento effettiva, raccogliere questo segnale ed eseguirlo. Ma come si collega la vista a questo segnale? Benvenuto nel sistema di segnali / slot di Qt. Si può ora concepire una classe manager (tipicamente una sorta di widget), che consiste in un oggetto di visualizzazione e un oggetto di calcolo dei dati (entrambi essendo QObjects), può eseguire connect (m_myDataEngine, &DataEngine::progressNotification, m_myViewObj, &SimpleView::displayProgress).

Non entriamo negli aspetti progettuali della classe manager, ma basti dire che è qui che brilla il sistema segnale / slot. Posso concentrarmi sulla progettazione di un'architettura molto pulita per la mia applicazione. Non sempre, ma spesso, trovo che emetto semplicemente segnali ma implemento slot .

Se è possibile utilizzare / chiamare un metodo di segnale senza mai emetterlo , significa necessariamente che non hai mai avuto bisogno di quella funzione come segnale in primo luogo.


6
No, in emiteffetti è solo una macro vuota e puramente facoltativa. Non così sono le parole chiave signale slotche vengono elaborate dal moc. signalserve per fornire l'implementazione della funzione, slotserve per creare la voce del meta oggetto in modo che si trovi con la SLOT(MySlot())macro o in QML. emitè un suggar sintattico. Niente si lamenterà mai se scrivi emit i++;(ma forse i tuoi colleghi) e ancora non riesci a connetterti i++.
derM

-5

La seconda opzione implica che tu sappia sempre qual è il nome della funzione ei parametri della funzione e che l'oggetto a cui lo stai inviando è conosciuto da quella particolare funzione. Questi due casi non sono sempre veri, quindi sono le due cose principali per cui sono stati creati slot e segnali. "sotto il cofano" il meccanismo di segnale e slot è solo un tavolo con i puntatori a ogni funzione collegata.

Inoltre, guarda questo pdf che spiega molto chiaramente la natura dei segnali e il meccanismo degli slot: http://www.elpauer.org/stuff/a_deeper_look_at_signals_and_slots.pdf


Entrambi i modi richiedono la conoscenza del nome del segnale e dei suoi parametri: lo stai emettendo, come potresti emettere qualcosa che non conosci? Entrambi hanno anche la stessa semantica, sono identici.
Mat

1
Forse stai incasinando una chiamata di segnale con una chiamata diretta allo slot? Ma devo ammettere che all'inizio mi chiedevo anche il titolo della domanda, dal momento che non sapevo che emitfosse solo un no-op. Ma anche in questo caso la lettura del corpo della domanda avrebbe dovuto chiarire le cose, quindi -1.
Christian Rau
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.