En esta página

Usando el Meta-Object Compiler (moc)

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

La herramienta moc lee un fichero de cabecera C++. Si encuentra una o más declaraciones de clase que contengan la macro Q_OBJECT, produce un archivo fuente C++ que contiene el código meta-objeto para esas clases. Entre otras cosas, el código metaobjeto es necesario para el mecanismo de señales y ranuras, la información de tipos en tiempo de ejecución y el sistema de propiedades dinámicas.

El archivo fuente C++ generado por moc debe compilarse y enlazarse con la implementación de la clase.

Tanto qmake como CMake generan makefiles con reglas de compilación que invocarán a moc en consecuencia, por lo que no necesitará utilizar moc directamente. qmake añadirá estas reglas de compilación por defecto, mientras que con CMake, puede utilizar la propiedad AUTOMOC para manejar moc automáticamente. Para más información sobre moc, vea ¿Por qué Qt usa Moc para señales y ranuras?

Uso

moc se usa típicamente con un archivo de entrada que contiene declaraciones de clase como esta:

class MyClass : public QObject
{
    Q_OBJECT

public:
    MyClass(QObject *parent = 0);
    ~MyClass();

signals:
    void mySignal();

public slots:
    void mySlot();
};

Además de las señales y ranuras mostradas anteriormente, moc también implementa propiedades de objeto como en el siguiente ejemplo. La macro Q_PROPERTY() declara una propiedad de objeto, mientras que Q_ENUM() declara una lista de tipos de enumeración dentro de la clase para ser utilizada dentro del sistema de propiedades.

En el siguiente ejemplo, declaramos una propiedad del tipo de enumeración Priority que también se llama priority y tiene una función get priority() y una función set setPriority().

class MyClass : public QObject
{
    Q_OBJECT
    Q_PROPERTY(Priority priority READ priority WRITE setPriority)

public:
    enum Priority { High, Low, VeryHigh, VeryLow };
    Q_ENUM(Priority)

    MyClass(QObject *parent = 0);
    ~MyClass();

    void setPriority(Priority priority) { m_priority = priority; }
    Priority priority() const { return m_priority; }

private:
    Priority m_priority;
};

La macro Q_FLAG() declara enumeraciones que se van a utilizar como indicadores, es decir, OR'd juntos. Otra macro, Q_CLASSINFO(), permite adjuntar pares nombre/valor adicionales al metaobjeto de la clase:

class MyClass : public QObject
{
    Q_OBJECT
    Q_CLASSINFO("Author", "Oscar Peterson")
    Q_CLASSINFO("Status", "Active")

public:
    MyClass(QObject *parent = 0);
    ~MyClass();
};

La salida producida por moc debe ser compilada y enlazada, al igual que el resto del código C++ de su programa; de lo contrario, la compilación fallará en la fase final de enlace. Si utiliza qmake, esto se hace automáticamente. Siempre que se ejecuta qmake, analiza los ficheros de cabecera del proyecto y genera reglas make para invocar moc para aquellos ficheros que contengan una macro Q_OBJECT. Del mismo modo, cuando se establece AUTOMOC a ON, CMake escaneará los archivos de cabecera y fuente en tiempo de compilación e invocará moc en consecuencia.

Si la declaración de la clase se encuentra en el archivo myclass.h, la salida moc se debe poner en un archivo llamado moc_myclass.cpp. Este archivo debe ser compilado como de costumbre, dando lugar a un archivo objeto, por ejemplo, moc_myclass.obj en Windows. Este objeto debe incluirse en la lista de archivos objeto que se enlazan en la fase final de construcción del programa.

Escribir reglas Make para invocar moc

Para cualquier cosa excepto los programas de prueba más simples, se recomienda que automatice la ejecución de moc. Añadiendo algunas reglas al makefile de su programa, make puede encargarse de ejecutar moc cuando sea necesario y de manejar la salida de moc.

Puedes usar CMake o qmake para generar makefiles que hagan todo el manejo necesario de moc.

Si quieres crear tus makefiles tú mismo, aquí tienes algunos consejos sobre cómo incluir el manejo de moc.

Para Q_OBJECT declaraciones de clase en archivos de cabecera, aquí hay una regla makefile útil si sólo utiliza GNU make:

moc_%.cpp: %.h
        moc $(DEFINES) $(INCPATH) $< -o $@

Si quieres escribir de forma portable, puedes usar reglas individuales de la siguiente forma:

moc_foo.cpp: foo.h
        moc $(DEFINES) $(INCPATH) $< -o $@

También debe recordar añadir moc_foo.cpp a su variable SOURCES (sustituya su nombre favorito) y moc_foo.o o moc_foo.obj a su variable OBJECTS.

Ambos ejemplos asumen que $(DEFINES) y $(INCPATH) se expanden a las opciones define e include path que se pasan al compilador C++. Estas son requeridas por moc para preprocesar los archivos fuente.

Aunque preferimos nombrar nuestros archivos fuente C++ .cpp, puede utilizar cualquier otra extensión, como .C, .cc, .CC, .cxx, y .c++, si lo prefiere.

Para las declaraciones de clase Q_OBJECT en archivos de implementación (.cpp), sugerimos una regla makefile como esta:

foo.o: foo.moc

foo.moc: foo.cpp
        moc $(DEFINES) $(INCPATH) -i $< -o $@

Esto garantiza que make ejecutará el moc antes de compilar foo.cpp. Entonces puede poner

#include "foo.moc"

al final de foo.cpp, donde todas las clases declaradas en ese archivo son completamente conocidas.

Opciones de línea de comandos

Aquí están las opciones de línea de comandos soportadas por el moc:

OpciónDescripción
-D<macro>[=<def>]Definir macro, con definición opcional.
-ESólo preprocesar; no generar código metaobjeto.
-f[<file>]Forzar la generación de una sentencia #include en la salida. Este es el valor predeterminado para los archivos de cabecera cuya extensión comienza con H o h. Esta opción es útil si tiene archivos de cabecera que no siguen las convenciones de nomenclatura estándar. La parte <file> es opcional.
-FdirmacOS. Añada el directorio de la estructura dir a la cabeza de la lista de directorios en los que se buscarán los archivos de cabecera. Estos directorios se intercalan con los especificados por las opciones -I y se buscan en un orden de izquierda a derecha (consulte la página de manual de gcc). Normalmente, utilice -F /Library/Frameworks/
-hMuestra el uso y la lista de opciones.
-iNo genera una sentencia #include en la salida. Esto se puede utilizar para ejecutar el moc en un archivo C++ que contenga una o más declaraciones de clase. A continuación, debe #include el código meta-objeto en el archivo .cpp.
-I<dir>Añadir dir a la ruta de inclusión de los archivos de cabecera.
-M<key=value>Añada metadatos adicionales a los plugins. Si una clase tiene Q_PLUGIN_METADATA especificado, el par clave-valor se añadirá a sus metadatos. Esto terminará en el objeto Json que se resuelve para el plugin en tiempo de ejecución (accesible desde QPluginLoader). Este argumento se utiliza normalmente para etiquetar plugins estáticos con información resuelta por el sistema de compilación.
-nwNo genera advertencias. (No se recomienda.)
-o<file>Escribe la salida a <file> en lugar de a la salida estándar.
-p<path>Hace que el moc anteponga <path>/ al nombre del fichero en la sentencia generada #include.
-U<macro>No define la macro.
@<file>Leer opciones de línea de comandos adicionales de <file>. Cada línea del archivo se trata como una única opción. Las líneas vacías se ignoran. Tenga en cuenta que esta opción no se admite dentro del propio archivo de opciones (es decir, un archivo de opciones no puede "incluir" otro archivo).
-vMostrar el número de versión de moc.

Puede indicar explícitamente al moc que no analice partes de un fichero de cabecera. moc define el símbolo de preprocesador Q_MOC_RUN. Cualquier código rodeado por

#ifndef Q_MOC_RUN
    ...
#endif

es omitido por moc.

Los diagnósticos

moc le advertirá sobre una serie de construcciones peligrosas o ilegales en las declaraciones de clase Q_OBJECT.

Si obtiene errores de enlace en la fase final de construcción de su programa, diciendo que YourClass::className() está indefinido o que YourClass carece de una vtable, algo se ha hecho mal. Lo más frecuente es que hayas olvidado compilar o #include el código C++ generado por moc, o (en el primer caso) incluir ese fichero objeto en la orden de enlace. Si utilizas qmake, intenta volver a ejecutarlo para actualizar tu makefile. Esto debería funcionar.

Sistemas de compilación

Incluyendo archivos moc de cabecera

qmake y CMake se comportan de manera diferente con respecto a la inclusión de archivos moc de cabecera.

Para ilustrar esto con un ejemplo, suponga que tiene dos cabeceras con sus correspondientes archivos fuente: a.h, a.cpp, b.h, y b.cpp. Cada cabecera tiene una macro Q_OBJECT:

// a.h
class A : public QObject
{
    Q_OBJECT

    public:
        // ...
};
// a.cpp
#include "a.h"

// ...

#include "moc_a.cpp"
// b.h
class B : public QObject
{
    Q_OBJECT

    public:
        // ...
};
// b.cpp
#include "b.h"

// ...

#include "moc_b.cpp"

Con qmake, si no incluye el archivo generado por moc (moc_a.cpp/moc_b.cpp), a.cpp, b.cpp, moc_a.cpp, y moc_b.cpp se compilarán por separado. Esto puede resultar en compilaciones más lentas. Si incluyes los archivos generados por moc, sólo a.cpp y b.cpp necesitarán ser compilados, ya que el código generado por moc está incluido en esos archivos.

Con CMake, si no incluyes los archivos, un único archivo adicional es generado por moc (llamémoslo cmake.cpp por el bien del ejemplo). cmake.cpp incluiría tanto moc_a.cpp como moc_b.cpp. Incluir el archivo generado por moc todavía está permitido con CMake, pero no es necesario.

Para más información sobre el soporte moc de CMake en relación a este tema, vea Incluyendo archivos moc de cabecera en los fuentes.

Limitaciones

moc no maneja todo C++. El principal problema es que las plantillas de clase no pueden tener la macro Q_OBJECT. He aquí un ejemplo:

class SomeTemplate<int> : public QFrame
{
    Q_OBJECT
    ...

signals:
    void mySignal(int);
};

Las siguientes construcciones son ilegales. Todas ellas tienen alternativas que pensamos que suelen ser mejores, por lo que eliminar estas limitaciones no es una gran prioridad para nosotros.

La herencia múltiple requiere que QObject sea el primero

Si está utilizando herencia múltiple, moc asume que la primera clase heredada es una subclase de QObject. Además, asegúrese de que sólo la primera clase heredada es una QObject.

// correct
class SomeClass : public QObject, public OtherClass
{
    ...
};

No se admite la herencia virtual con QObject.

Los punteros de función no pueden ser parámetros de señal o ranura

En la mayoría de los casos en los que se considera el uso de punteros de función como parámetros de señal o ranura, creemos que la herencia es una alternativa mejor. He aquí un ejemplo de sintaxis ilegal:

class SomeClass : public QObject
{
    Q_OBJECT

public slots:
    void apply(void (*apply)(List *, void *), char *); // WRONG
};

Puede evitar esta restricción de la siguiente manera:

typedef void (*ApplyFunction)(List *, void *);

class SomeClass : public QObject
{
    Q_OBJECT

public slots:
    void apply(ApplyFunction, char *);
};

A veces puede ser incluso mejor sustituir el puntero a función por herencia y funciones virtuales.

Los Enums y Typedefs deben estar completamente cualificados para los parámetros de señal y ranura

Al comprobar las firmas de sus argumentos, QObject::connect() compara los tipos de datos literalmente. Así, Alignment y Qt::Alignment se tratan como dos tipos distintos. Para evitar esta limitación, asegúrese de calificar completamente los tipos de datos al declarar señales y ranuras, y al establecer conexiones. Por ejemplo

class MyClass : public QObject
{
    Q_OBJECT

    enum Error {
        ConnectionRefused,
        RemoteHostClosed,
        UnknownError
    };

signals:
    void stateChanged(MyClass::Error error);
};

Las clases anidadas no pueden tener señales o ranuras

He aquí un ejemplo de la construcción infractora:

class A
{
public:
    class B
    {
        Q_OBJECT

    public slots:   // WRONG
        void b();
    };
};

Los tipos de retorno de señales/ranuras no pueden ser referencias

Las señales y ranuras pueden tener tipos de retorno, pero las señales o ranuras que devuelvan referencias serán tratadas como si devolvieran void.

Sólo las señales y las ranuras pueden aparecer en las secciones signals y slots de una clase.

moc se quejará si intentas poner otras construcciones en las secciones signals o slots de una clase que no sean señales y ranuras.

Ver también Sistema de Meta-Objetos, Señales y Slots, y Sistema de Propiedades de Qt.

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.