Qt moc mit Implementierungen innerhalb von Header-Dateien?
Frage
Ist es möglich, der Qt MOC zu sagen, dass ich die Klasse erklären möchte und implementieren sie in einer einzigen Datei statt Spaltung sie in eine .h und CPP-Datei?
Lösung 4
Ich glaube, dies ist der beste Weg zu sein. Es ist eigentlich wie ich jetzt alle meine Objekte konstruieren.
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
Erstellen ... qmake Works.pro
make
Andere Tipps
Wenn Sie eine QObject Unterklasse deklarieren und implementieren möchten in Sie CPP-Datei, müssen Sie umfassen manuell die moc-Datei.
Zum Beispiel: (Datei main.cpp)
struct SubObject : QObject
{
Q_OBJECT
};
//...
#include "main.moc"
Sie müssen erneut ausführen moc (make qmake
) nach der #include
Anweisung hinzugefügt wird.
TL; DR
Ja, wenn Sie nur über die Dateien im Gespräch, dass Sie selbst schreiben (wie die von moc erzeugte entgegengesetzt). Sie gar nicht zu tun etwas Besonderes benötigen.
Wenn Sie jemals moc Ausgabe explizit in den Dateien aufnehmen möchten Sie schreiben, gibt es einen Fall, in dem Sie muss es tun, und ein Fall, in dem Sie Macht Wunsch es zu tun. Nehmen wir an, dass MyObject
Klasse in MyObject.h
und Ihre Definition davon erklärt wird, in MyObject.cpp
gegeben:
-
MyObject.moc
muss enthalten am Ende vonMyObject.cpp
iff Sie erklären alleQ_OBJECT
Klassen innerhalbMyObject.cpp
. -
moc_MyObject.cpp
können sein eingeschlossen überall inMyObject.cpp
die Anzahl der Übersetzungseinheiten in Ihrem Projekt zu halbieren. Es ist eine Build-Zeitoptimierung nur. Wenn Sie es nicht tun, wirdmoc_MyObject.cpp
separat kompiliert werden.
Jedes Mal, wenn Sie hinzufügen oder entfernen Q_OBJECT
Makro aus einer beliebigen Quelle oder Headerdatei, oder Sie hinzufügen oder explizite Einschlüsse von moc Ausgabe in solchen Dateien entfernen, müssen Sie erneut ausgeführt Qmake / cmake.
Um re-run Qmake / cmake in Qt Creator, einfach mit der rechten Maustaste auf das Toplevel-Projekt, und wählen Sie Ausführen Qmake oder Ausführen Cmake aus dem Kontextmenü.
Die einfache Antwort
Ein Beispiel qmake-basierte Qt-Projekt von drei Dateien bestehen könnte, wie folgt:
# 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
Es ist nicht viel, aber es ist sicherlich gültig. Neben den verschiedenen Bibliotheken, dass das Build-System verbindet unser Projekt mit, gibt es zwei projektspezifische eine Definitionsregel , um genau zu sein, und so ergibt sich eine ungültige C ++ Programm.
Nun könnte man denken, „clever“ zu bekommen und sind gewaltsam die moc Ausgabe in der Header-Datei. Die Qmake / Cmake / QBS werden aufnimmt, und wird dies erkennen und wird nicht separat moc Ausgabe durch den Compiler verarbeitet beliebigemehr, wie Sie es bereits getan haben.
So wird angenommen, dass in dem Projekt oben, Sie myobject.h
geändert und lautet wie folgt:
// 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
Wie es aussieht, wird das Projekt noch kompilieren, scheinbar erfüllen Ihr Ziel nur eine Datei zu haben, die die Gesamtheit der MyObject
definiert - die Bits, die Sie geschrieben haben, und die Bits, dass moc erzeugt, beide. Aber es ist nur aufgrund eines unwahrscheinlich glücklichen Umstand: der Inhalt moc_*.cpp
ist nach wie vor nur in einer Übersetzungseinheit -
Nehmen wir jetzt an, dass wir eine zweite Quelldatei zu unserem Projekt hinzufügen:
# test.pro
QT += core
CONFIG += console
CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cpp test.cpp
HEADERS += myobject.h
// test.cpp
#include "myobject.h"
Nicht viel zu. Es sollte funktionieren, auch wenn es nicht viel tun, nicht wahr?
Ach, es wird nicht verknüpfen. Nun werden die Inhalte von moc_myobject.cpp
sind ein Teil von zwei Übersetzungseinheiten. Da moc_myobject.cpp
Innenseiten voller Stand-alone-Klasse Mitglied Definitionen sind, verletzt dies die eine Definitionsregel . Die Regel Mandate, dass eigenständige Definitionen nur in eine Übersetzungseinheit innerhalb eines Ziels erscheinen. Der Linker, wobei die Hüter dieser Regel zu Recht beklagt.
Auf Einschließlich moc Ausgabe in der CPP-Datei
Wie angedeutet in der TL; DR., Keiner der oben verbietet ausdrücklich die Aufnahme von moc Ausgabe in Quelle (CPP) Dateien unter bestimmten Umständen
Bei „foo.h“ und „foo.cpp“ und ein Projekt von qmake oder cmake verwalten, wird das Build-System moc
direkt auf zwei Ausgänge zur Erzeugung von bis:
-
moc_foo.cpp
vonfoo.h
, ifffoo.h
enthältQ_OBJECT
Makro. -
foo.moc
vonfoo.cpp
, ifffoo.cpp
enthält#include "foo.moc"
.
Lassen Sie uns im Detail untersuchen, warum würden Sie entweder ein in einer CPP-Datei aufgenommen werden sollen.
Einschließlich xxx.moc
Manchmal, vor allem in den Tagen vor der C ++ 11 und Qt 5, kommt es praktisch nur kleine Helfer QObject Klassen für die lokalen Gebrauch innerhalb einer Übersetzungseinheit (Quelldatei) zu erklären.
Dies ist auch praktisch, wenn Single-Datei zu schreiben, in sich geschlossene Testfälle und Beispiele für Stackoverflow Verwendung.
Angenommen, Sie jemand wollte zu zeigen, in einer Datei, wie ein Schlitz von der Ereignisschleife aufgerufen werden:
// 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"
Da MyObject
eine kleine Klasse, die nur lokal in main.moc
verwendet wird, wäre es nicht viel Sinn, seine Definition in einem separaten Header-Datei zu setzen. Die #include "main.moc"
Linie wird von qmake / cmake bemerkt werden, und main.cpp
wird durch moc zugeführt werden, in main.moc
führt. Da main.moc
definiert Mitglieder MyObject
, muss es irgendwo aufgenommen werden, wo MyObject
deklariert wird. Da die Erklärung innerhalb main.cpp
ist, können Sie keine separate Übersetzungseinheit sein main.moc
: es aufgrund MyObject
nicht kompiliert werden nicht erklärt zu werden. Der einzige Ort, an dem es deklariert wird, ist innerhalb main.cpp
, irgendwo gegen Ende. Deshalb ist es immer eine sichere Wette, gehört foo.moc
am Ende foo.cpp
.
Eine aufmerksame Leser fragt nun: wie kommt moc_foo.cpp
die Deklarationen der Klassen, deren Mitglieder wird es definiert? Ganz einfach: es schließt ausdrücklich die Header-Datei wird erzeugt aus (hier: foo.h
). Natürlich foo.moc
kann das nicht tun, da sie durch Multiplikation definieren, alles in foo.cpp
die einzige Definition Regel brechen würde.
Einschließlich moc_xxx.cpp
Bei besonders großen Qt-Projekten, die Sie haben könnten - im Durchschnitt - zwei Dateien und zwei Übersetzungseinheiten für jede Klasse:
-
MyObject.h
undMyObject.cpp
sind die Dateien, die Sie schreiben. -
MyObject.cpp
undmoc_MyObject.cpp
sind die Übersetzungseinheiten.
Es ist möglich, die Anzahl der Übersetzungseinheiten zu halbieren, indem Sie explizit moc_MyObject.cpp
irgendwo in MyObject.cpp
einschließlich:
// MyObject.cpp
#include "MyObject.h"
#include "moc_MyObject.cpp"
...
Ich glaube, Sie können in der Regel erklären und die Klasse in der Header-Datei zu implementieren, ohne etwas Besonderes, zB:
#include <QObject>
class MyClass : public QObject
{
Q_OBJECT
public:
MyClass(QObject * parent)
{
// Constructor Content
}
methodExample()
{
// Method content
}
};
Danach Sie die Header-Datei in die pri-Datei hinzufügen und führen Sie qmake wieder und das ist es. Sie haben eine Klasse, die erbt von QObject und umgesetzt wird und int er .h-Datei deklariert.