¿Qué hace la macro Q_OBJECT? ¿Por qué todos los objetos Qt necesitan esta macro?

131

Acabo de comenzar a usar Qt y noté que todas las definiciones de clase de ejemplo tienen la macro Q_OBJECTcomo la primera línea. ¿Cuál es el propósito de esta macro de preprocesador?

Trevor Boyd Smith
fuente
25
QT se refiere a QuickTime y Qt se refiere a la biblioteca de C ++ llamada Qt.
Bleadof

Respuestas:

132

De la documentación de Qt :

El compilador Meta-Object, moc, es el programa que maneja las extensiones C ++ de Qt.

La herramienta moc lee un archivo de encabezado C ++. Si encuentra una o más declaraciones de clase que contienen la macro Q_OBJECT, genera un archivo fuente C ++ que contiene el código del metaobjeto para esas clases. Entre otras cosas, se requiere un código de metaobjeto para el mecanismo de señales y ranuras, la información del tipo de tiempo de ejecución y el sistema de propiedades dinámicas.

Stu Mackellar
fuente
¿Por qué no necesito escribir explícitamente Q_OBJECT::connect()sino simplemente connect()?
mLstudent33
19

Simplemente le dice al precompilador que esta clase tiene elementos de interfaz gráfica de usuario y debe ejecutarse a través del 'moc', solo necesita agregar esto a las clases que usan el mecanismo de señal / ranura.
Pero será ignorado silenciosamente en cualquier otra clase, solo aumenta el tiempo de construcción.

Martin Beckett
fuente
3
También es falso que solo lo necesite en clases que usan el mecanismo de señal / ranura. La ausencia de Q_OBJECTrupturas qobject_caste introspección. Puede conducir a un comportamiento desconcertante, por lo que es una mala idea.
Mónica
2
No es cierto que Q_OBJECTse ignorará "en silencio" en cualquier otra QObjectclase (no ). De acuerdo con el estándar C ++, introduce un comportamiento indefinido al declarar varias funciones y variables miembro que nunca se definen. También contamina el espacio de nombres de su clase con QObjectmiembros específicos. Por ejemplo, un Q_OBJECTbien puede romper una clase no relacionada que contiene un método llamado metaObject.
Mónica
2
Eso está mal. Aunque probablemente desee equipar la mayoría de las clases gui con la Q_OBJECTmacro, tiene mucho sentido tener clases no gui con la macro, así como clases gui sin la macro. La macro es útil, pero no está limitada ni es necesaria para las clases gui.
pasbi
9

El MOC (compilador de metaobjetos) convierte los archivos de encabezado incluidos en la macro Q_OBJECT en código fuente equivalente de C ++. Básicamente controla el mecanismo de ranura de señal y lo hace comprensible para el compilador de C ++

aditya
fuente
2
Eso es falso: el Q_OBJECTcompilador expande la macro, no se necesita moc para eso. El moc no hace nada con la macro en sí, pero genera las definiciones de las variables miembro y los métodos que la Q_OBJECTmacro ha declarado .
Mónica
5

1 De la documentación de Qt del sistema Meta-Object

La herramienta moc lee un archivo fuente C ++. Si encuentra una o más declaraciones de clase que contienen la macro Q_OBJECT, genera otro archivo fuente C ++ que contiene el código del metaobjeto para cada una de esas clases. Este archivo fuente generado # se incluye en el archivo fuente de la clase o, más habitualmente, se compila y vincula con la implementación de la clase.

2 De la documentación de Qt de THE Q_OBJECT

La macro Q_OBJECT debe aparecer en la sección privada de una definición de clase que declara sus propias señales y ranuras o que utiliza otros servicios proporcionados por el sistema de metaobjetos de Qt.

3 De la documentación de Qt de moc

La herramienta moc lee un archivo de encabezado C ++. Si encuentra una o más declaraciones de clase que contienen la macro Q_OBJECT, genera un archivo fuente C ++ que contiene el código del metaobjeto para esas clases. Entre otras cosas, se requiere un código de metaobjeto para el mecanismo de señales y ranuras, la información del tipo de tiempo de ejecución y el sistema de propiedades dinámicas.

4 De la documentación de Qt de señales y ranuras

El preprocesador expande la macro Q_OBJECT para declarar varias funciones miembro que implementa el moc; si obtiene errores del compilador en la línea de "referencia indefinida a vtable para LcdNumber", probablemente haya olvidado ejecutar el moc o incluir la salida de moc en el comando de enlace.

Bob Zhang
fuente
2

En gcc with -Epuedes ver macros expandidas. Esto es lo que se Q_OBJECTexpande en gcc en Linux. Tenga en cuenta que esto puede depender de la plataforma y puede cambiar según la versión de QT. Puede ver que no es solo una etiqueta para el compilador de moc.

# 11 "mainwindow.hh"
#pragma GCC diagnostic push
# 11 "mainwindow.hh"

# 11 "mainwindow.hh"
#pragma GCC diagnostic ignored "-Wsuggest-override"
# 11 "mainwindow.hh"
    static const QMetaObject staticMetaObject; virtual const QMetaObject *metaObject() const; virtual void *qt_metacast(const char *); virtual int qt_metacall(QMetaObject::Call, int, void **); static inline QString tr(const char *s, cons
t char *c = nullptr, int n = -1) { return staticMetaObject.tr(s, c, n); } __attribute__ ((__deprecated__)) static inline QString trUtf8(const char *s, const char *c = nullptr, int n = -1) { return staticMetaObject.tr(s, c, n); } private:
# 11 "mainwindow.hh"
#pragma GCC diagnostic ignored "-Wattributes"
# 11 "mainwindow.hh"
    __attribute__((visibility("hidden"))) static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **);
# 11 "mainwindow.hh"
#pragma GCC diagnostic pop
# 11 "mainwindow.hh"
    struct QPrivateSignal {};
Arne
fuente
0

La macro Q_OBJECT debe aparecer en la sección privada de una definición de clase que declara sus propias señales y ranuras o que utiliza otros servicios proporcionados por el sistema de metaobjetos de Qt.

Andres
fuente
1
Esto es engañoso: la Q_OBJECTmacro debe aparecer en cada clase de la que se deriva QObject. Su código se romperá sutilmente cuando la macro esté ausente, y solo porque se compila no lo hace correcto.
Vuelva a instalar Mónica
@KubaOber, ¿tiene un ejemplo de código que se compila pero no funciona cuando Q_OBJECTfalta la macro?
Chris
2
Si observa la implementación de Q_OBJECT, encontrará que utiliza especificadores de acceso. Así que si la macro debe aparecer en menos del private, protectedo publicespecificadores es irrelevante - es sólo convención para colocarlo a la cabeza de la clase.
TrebledJ