moc qt con implementaciones dentro de los archivos de cabecera?
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?
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
:
-
MyObject.moc
debe ser incluye al final deMyObject.cpp
si y sólo si se declara ninguna claseQ_OBJECT
dentroMyObject.cpp
. -
moc_MyObject.cpp
puede ser incluye en cualquier lugar enMyObject.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:
-
moc_foo.cpp
defoo.h
, ifffoo.h
contiene macroQ_OBJECT
. -
foo.moc
defoo.cpp
, ifffoo.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
yMyObject.cpp
son los archivos que usted escribe. -
MyObject.cpp
ymoc_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.