Pregunta

¿Es posible contar la Qt MOC que me gustaría declarar la clase y ponerlo en práctica en un único archivo en lugar de dividirlos en un archivo .cpp y .h?

¿Fue útil?

Solución 4

Creo que esta es la mejor manera. Es realmente cómo construyo todos mis objetos ahora.

Qt 4.8.7

Works.pro:

SOURCES += \
    main.cpp

HEADERS += \
    Window.h \
    MyWidget.h

main.cpp

#include <QtGui>
#include "Window.h"

int main(int argc, char *argv[])
{
    QApplication app(argc,argv);

    Window window;
    window.show();
    return app.exec();
}

Window.h

#ifndef WINDOW_H
#define WINDOW_H

#include <QtGui>
#include "MyWidget.h"

class Window : public QWidget
{
    Q_OBJECT

private:
    MyWidget *whatever;

public:
    Window()
    {
        QHBoxLayout *layout = new QHBoxLayout;
        setLayout(layout);

        whatever = new MyWidget("Screw You");
        layout->addWidget(whatever);

    }
};

#include "moc_Window.cpp"

#endif // WINDOW_H

MyWidget.h

#ifndef MYWIDGET_H
#define MYWIDGET_H

#include <QtGui>

class MyWidget : public QLabel
{
    Q_OBJECT

public:
    MyWidget(QString text) : QLabel(text)
    {
        // Whatever
    }
};

#include "moc_MyWidget.cpp"

#endif // MYWIDGET_H

Construir ... qmake Works.pro

make

Otros consejos

Si desea declarar y poner en práctica una subclase QObject en que cpp, usted tiene que incluir manualmente el archivo moc.

Por ejemplo: (archivo main.cpp)

struct SubObject : QObject
{
    Q_OBJECT
};

//...

#include "main.moc"

Hay que volver a ejecutar moc (make qmake) después de añadir la declaración #include.

TL; DR

Sí, si usted está hablando sólo de los archivos que se escribe a sí mismo (al contrario que los generados por MOC). Usted no tiene que hacer nada en absoluto especial.

Si en algún momento desea incluir la producción moc explícitamente en los archivos que usted escribe, hay un caso en el que debe hacerlo, y un caso en el que podría deseo para hacerlo. Supongamos que la clase MyObject se declara en MyObject.h y su definición de la misma se da en MyObject.cpp:

  1. MyObject.moc debe ser incluye al final de MyObject.cpp si y sólo si se declara ninguna clase Q_OBJECT dentro MyObject.cpp.

  2. moc_MyObject.cpp puede ser incluye en cualquier lugar en MyObject.cpp reducir a la mitad el número de unidades de traducción en su proyecto. Es sólo una optimización en tiempo de compilación. Si no lo hace, moc_MyObject.cpp será compilado por separado.

Cada vez que se añade o macro quitar Q_OBJECT desde cualquier fuente o archivo de cabecera, o añadir o eliminar inclusiones explícitas de salida moc en este tipo de archivos, debe volver a ejecutar qmake / cmake.

Para volver a ejecutar qmake / cmake en Qt Creator, simplemente haga clic en el proyecto de nivel superior, y seleccione Ejecutar qmake o Ejecutar cmake en el menú contextual.

La respuesta simple

Un ejemplo de proyecto basado en Qt qmake podría consistir en tres archivos, de la siguiente manera:

# test.pro
QT       += core
CONFIG   += console
CONFIG   -= app_bundle
TEMPLATE = app
SOURCES += main.cpp
HEADERS += myobject.h

// main.cpp
#include "myobject.h"

int main() {
  MyObject obj;
  obj.staticMetaObject; // refer to a value defined in moc output
  return 0;
}

// myobject.h
#ifndef MYOBJECT_H
#define MYOBJECT_H
#include <QObject>

class MyObject : public QObject {
   Q_OBJECT
public:
   MyObject() {}
   Q_SLOT void aSlot() {}
};

#endif // MYOBJECT_H

No hace mucho, pero es sin duda válida. Aparte de las diferentes bibliotecas que el sistema de construcción de enlaces con nuestro proyecto, hay dos proyectos específicos unidades de traducción : main.cpp y moc_myobject.cpp

.

A pesar de que parece que toda la implementación de MyObject está en el archivo de cabecera, en realidad no lo es. La macro Q_OBJECT declara algunos bits de la aplicación que se indefinida, si no fuera por las definiciones generada moc.

¿Cómo moc entrar en el cuadro? Cuando el proyecto se construye en primer lugar, la herramienta metapaquete - ya sea qmake o cmake - escanea todos los archivos de entrada de C ++ para la presencia de macro Q_OBJECT. Aquellos que lo contienen, se les da un tratamiento especial. En este ejemplo de proyecto, myobject.h contiene Q_OBJECT y se procesa a través moc en moc_myobject.cpp. Este último se añade a la lista de fuentes que son compilados por el compilador C ++. Es sólo conceptualmente, como si se hubiera SOURCES += moc_myobject.cpp en el archivo .pro. Por supuesto, nunca se debe añadir una línea como en el archivo .pro.

Ahora aviso de que el toda aplicación de restos MyObject en dos archivos: myobject.h y moc_myobject.cpp. myobject.h puede incluirse en otras tantas unidades de traducción como usted desea - porque no hay definiciones (independiente) fuera de la clase que violación de la norma una definición. La trata de sistemas de construcción moc_myobject.cpp como una única unidad de traducción, por separado -. Esto es todos los cuidados para usted

Así, su objetivo es alcanzado con ningún esfuerzo en absoluto: No tiene nada especial que hacer para poner toda la implementación de MyObject - excepto por los bits que produce moc - en el archivo de cabecera. Se puede prolongar los tiempos de compilación, pero es inocua.

Un enfoque Regla-Violar

una regla definición , para ser exactos, y de este modo se obtiene un C ++ no válido programa.

Ahora usted podría pensar para conseguir "inteligente" e incluir a la fuerza la salida de moc en el archivo de cabecera. El qmake / cmake / SBC será servicial, y detectará esto y no procesará por separado salida moc a través del compilador cualquierAdemás, como ya lo ha hecho.

Por lo tanto, se supone que, en el proyecto anterior, ha cambiado myobject.h que diga lo siguiente:

// myobject.h
#ifndef MYOBJECT_H
#define MYOBJECT_H
#include <QObject>

class MyObject : public QObject {
   Q_OBJECT
public:
   MyObject() {}
   Q_SLOT void aSlot() {}
};

#include "moc_myobject.cpp"
#endif // MYOBJECT_H

En su forma actual, el proyecto todavía compilar, aparentemente el cumplimiento de su objetivo de tener sólo un archivo que define la totalidad de MyObject - los bits que escribió, y los bits que generan moc, ambos. Pero es sólo debido a una circunstancia feliz poco probable: el contenido de moc_*.cpp se encuentran todavía en una sola unidad de traducción -

Supongamos ahora que se añade un segundo archivo fuente a nuestro proyecto:

# test.pro
QT       += core
CONFIG   += console
CONFIG   -= app_bundle
TEMPLATE = app
SOURCES += main.cpp test.cpp
HEADERS += myobject.h

// test.cpp
#include "myobject.h"

No hay mucho a ella. Se debe trabajar, incluso si no hace mucho, ¿verdad?

Por desgracia, no va a enlazar. Ahora el contenido de moc_myobject.cpp son una parte de dos unidades de traducción. Desde las entrañas de moc_myobject.cpp están llenos de definiciones de miembros de clase independiente, esto viola la una regla definición . Los mandatos de reglas que las definiciones independientes pueden aparecer sólo en una unidad traducción dentro de un objetivo. El enlazador, siendo el guardián de esta regla, se queja con razón.

en la inclusión de moc salida en el archivo .cpp

Como se ha aludido en el TL;. DR, ninguno de los anteriores se opone inclusión explícita de salida moc en archivos de origen (.cpp), en circunstancias específicas

Dada "foo.h" y "foo.cpp", y un proyecto gestionado por qmake o cmake, el sistema de construcción dirigirá moc para generar hasta dos salidas:

  1. moc_foo.cpp de foo.h, iff foo.h contiene macro Q_OBJECT.

  2. foo.moc de foo.cpp, iff foo.cpp contiene #include "foo.moc".

Vamos a examinar en detalle por qué le gustaría incluir cualquiera de los dos en un archivo .cpp.

Incluyendo xxx.moc

A veces, especialmente en los días previos a C ++ y Qt 11 5, que es muy útil para declarar pequeñas clases de ayuda QObject para uso local dentro de una unidad de traducción (archivo de origen) solamente.

Esto también es muy útil cuando se escribe en fila india, casos de prueba independientes y ejemplos para su uso stackoverflow.

Supongamos que deseaba a alguien para demostrar, en un solo archivo, cómo invocar una ranura del bucle de eventos:

// main.cpp
#include <QCoreApplication>
#include <QTextStream>
#include <cstdio>

QTextStream out(stdout);

class MyObject : public QObject {
  Q_OBJECT
public:
  MyObject() {}
  Q_SLOT void mySlot() { out << "Hello from " << __FUNCTION__ << endl; }
};

int main(int argc, char ** argv) {
  QCoreApplication app(argc, argv);
  MyObject obj;
  QMetaObject::invokeMethod(&obj, Qt::QueuedConnection, "mySlot");
  QMetaObject::invokeMethod(&app, Qt::QueuedConnection, "quit");
  return app.exec();
}

#include "main.moc"

Desde MyObject es una pequeña clase que sólo se utiliza localmente en main.moc, no tendría mucho sentido para poner su definición en un archivo de cabecera por separado. La línea #include "main.moc" será observado por qmake / cmake, y main.cpp se alimenta a través de moc, resultando en main.moc. Puesto que define los miembros de main.moc MyObject, debe ser incluido en algún lugar donde se declara MyObject. A medida que la declaración está dentro main.cpp, no se puede tener main.moc ser una unidad separada traducción: no se compilará debido a ser MyObject no declarado. El único lugar donde se declara está dentro main.cpp, en algún lugar hacia el final. Es por eso que es una apuesta segura que siempre incluyen foo.moc al final de foo.cpp.

Un lector astuto ahora pregunta: ¿cómo es que se moc_foo.cpp las declaraciones de las clases cuyos miembros se define? En pocas palabras: se incluye explícitamente el archivo de cabecera que se genera a partir de (aquí: foo.h). Por supuesto foo.moc no puede hacer eso, ya que rompería la regla definición única mediante la definición de multiplicar todo en foo.cpp.

Incluyendo moc_xxx.cpp

En particular, los grandes proyectos de Qt, que podría tener - en promedio - dos archivos y dos unidades de traducción por cada clase:

  • MyObject.h y MyObject.cpp son los archivos que usted escribe.
  • MyObject.cpp y moc_MyObject.cpp son las unidades de traducción.

Es posible reducir a la mitad el número de unidades de traducción al incluir explícitamente en algún lugar en moc_MyObject.cpp MyObject.cpp:

// MyObject.cpp
#include "MyObject.h"
#include "moc_MyObject.cpp"
...

Creo que normalmente puede declarar e implementar la clase en el archivo de cabecera sin utilizar nada especial, por ejemplo:

#include <QObject>

class MyClass : public QObject
{
  Q_OBJECT

  public:
     MyClass(QObject * parent)
     {
        // Constructor Content
     }

     methodExample()
     {
          // Method content
     }
};

Después de esto se agrega el archivo de cabecera en el fichero de PRI y ejecutar qmake de nuevo y eso es todo. Usted tiene una clase que hereda de QObject y se implementa y declararon que int .h archivo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top