2012-04-15 11 views
70

Digamos que tengo esta señal:Uso emiten una señal vs llamando como si fuera una función regular en Qt

signals: 
    void progressNotification(int progress); 

sólo recientemente he aprendido acerca de la palabra clave emitir en Qt. Hasta ahora, solía ejecutar señales simplemente llamándolas como una función normal. Así que en lugar de:

emit progressNotification(1000 * seconds); 

que iba a escribir:

progressNotification(1000 * seconds); 

Llamándolos así parecía funcionar, y todas las ranuras conectados ejecutaría, también lo hace usando la palabra clave emiten causar un comportamiento diferente, o ¿es solo azúcar sintáctico?

+11

+1 Nunca se supo que 'emit' no es necesario. Sin embargo, es extraño que hayas aprendido a 'emit' mucho después de llamar directamente a las señales, ya que el sistema de ranura de señal es una de las primeras cosas que se aprende sobre Qt. –

Respuesta

61

emit es sólo azúcar sintáctico. Si observa la salida de la función preprocesada que emite una señal, verá que emit acaba de desaparecer.

La "magia" ocurre en el código generado para la función de emisión de señal, que se puede ver inspeccionando el código C++ generado por moc.

Por ejemplo una señal de foo sin parámetros genera esta función de miembro:

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

Y el código emit foo(); es pre-procesado simplemente foo();

emit se define en Qt/qobjectdefs.h (en el de código abierto sabor de la fuente de todos modos), como este:

#ifndef QT_NO_EMIT 
# define emit 
#endif 

(El protector de definición es para permitirle usar Qt con otros marcos que tienen nombres colisionantes a través de la opción de configuración QMake no_keywords)

+11

¿Sabes si alguna vez hubo una implementación (o una implementación planificada) de un 'emit' que realmente hizo más que nada? Encuentro que tener el "azúcar sintáctico" en este caso solo confunde al principiante (o al menos a mí cuando era un usuario de Qt novato) - parece que algo mágico o importante está sucediendo con la pseudo-palabra clave 'emit', cuando no hace nada en absoluto: toda la magia ocurre en una función antigua normal que 'moc' crea (' moc' es la magia para las señales Qt y las ranuras). 'emit' es una decoración innecesaria que no hace más que parecer importante. –

+8

Emitir _no_ "solo decoración". 'emit' le dice a la persona que lee la llamada que la magia está a punto de suceder (es decir, va a desencadenar código en objetos de los que esta clase posiblemente nunca haya oído hablar, y estas llamadas pueden ser síncronas o asíncronas), lo cual se pierde por completo si omite la palabra clave Úselo. Es auto-documentación. Los "novatos" deberían leer documentos y tutoriales, y 'emit' siempre está ahí (en los documentos oficiales de todos modos). Descubrir que puedes llamar simplemente a la función debería suceder después de que hayas "visto la luz": ya no eres un novato en ese momento. – Mat

+14

Hmm, no estoy seguro de estar de acuerdo con usted en lo valiosa que es la palabra clave 'emit'. Creo que hubiera preferido que se utilizara una convención de nomenclatura si fuera necesario aclarar que una llamada a función es una señal. –

-4

La segunda opción implicaría que usted siempre sabe cuál es el nombre de la función y los parámetros de la función y que el objeto al que lo está enviando es conocido por esa función en particular. Esos dos casos no siempre son ciertos, así que esas son las dos principales razones por las cuales se han hecho ranuras y señales. "debajo del capó" el mecanismo de señal y ranura es solo una tabla con punteros para cada función que está conectada.

También, busque en este pdf que explica muy claramente la naturaleza del mecanismo de señales y slots: http://www.elpauer.org/stuff/a_deeper_look_at_signals_and_slots.pdf

+0

Ambas formas requieren conocer el nombre de la señal y sus parámetros: la está emitiendo, ¿cómo podría emitir algo que no sabe? Ambos tienen la misma semántica, son idénticos. – Mat

+0

¿Quizás estás estropeando una llamada de señal con una llamada directa? Pero tengo que admitir que también me pregunté sobre el título de la pregunta al principio, ya que nunca supe que 'emit' fuera simplemente no-operativo. Pero incluso en este caso, leer el cuerpo de la pregunta debería haber aclarado las cosas, entonces -1. –

3

Después de 18 meses ... Comencé con comentarios con la respuesta de @ Mat y me estaba quedando sin respuesta de habitación rápidamente. Por lo tanto, la respuesta.

OMI emit es ni azúcar sintáctico ni una palabra clave simple en el sentido de que

  1. Genera código (según lo explicado por @Mat arriba),
  2. Ayuda a que el mecanismo de connect reconocen que, efectivamente, se trata de una signal y
  3. Hace que su señal sea parte de un sistema "más grande", donde las señales y respuestas (ranuras) se pueden ejecutar de forma síncrona o sincronizada, o en cola, dependiendo de dónde y cómo se emitió la señal. Esta es una característica extremadamente útil del sistema de señal/ranura.

Todo el sistema de señal/ranura es un idioma diferente al de una llamada de función simple. Yo creo que se deriva del patrón del observador. También existe una gran diferencia entre signal y slot: una señal no tiene que implementarse, mientras que una ranura debe ser.

Está caminando por la calle y ve una casa en llamas (una señal). Marque 911 (conecte la señal de fuego con la ranura de respuesta 911). La señal fue solo emitió, mientras que la ranura se implementó por el departamento de bomberos. Puede ser impreciso, pero entiendes la idea. Miremos el ejemplo de OP.

Algún objeto de back-end sabe cuánto progreso se ha realizado. Por lo tanto, podría simplemente la señal emit progressNotification(...). Depende de la clase que muestre la barra de progreso real, para recoger esta señal y ejecutarla. Pero, ¿cómo se conecta la vista a esta señal? Bienvenido al sistema de señal/ranura de Qt. Ahora se puede concebir una clase de administrador (generalmente un artilugio de géneros), que consiste en un objeto de vista y un objeto de cálculo de datos (ambos siendo QObjects), puede realizar connect (m_myDataEngine, &DataEngine::progressNotification, m_myViewObj, &SimpleView::displayProgress).

No entremos en los aspectos de diseño de la clase de administrador, pero basta con decir que aquí es donde brilla el sistema de señal/ranura. Puedo centrarme en diseñar una arquitectura muy limpia para mi aplicación. No siempre, pero muchas veces, me parece que I simplemente emiten señales pero implementan las ranuras.

Si es posible utilizar/llamar a un método de señal sin tener que emitirla, entonces necesariamente implica que que nunca necesitamos que funcionan como una señal en el primer lugar.

Cuestiones relacionadas