Was macht das Q_OBJECT-Makro? Warum benötigen alle Qt-Objekte dieses Makro?

131

Ich habe gerade mit Qt angefangen und festgestellt, dass alle Beispielklassendefinitionen das Makro Q_OBJECTals erste Zeile haben. Was ist der Zweck dieses Präprozessor-Makros?

Trevor Boyd Smith
quelle
25
QT bezieht sich auf QuickTime und Qt bezieht sich auf die C ++ - Bibliothek namens Qt.
Bleadof

Antworten:

132

Aus der Qt-Dokumentation :

Der Meta-Object Compiler, moc, ist das Programm, das die C ++ - Erweiterungen von Qt verarbeitet.

Das moc-Tool liest eine C ++ - Headerdatei. Wenn eine oder mehrere Klassendeklarationen gefunden werden, die das Q_OBJECT-Makro enthalten, wird eine C ++ - Quelldatei erstellt, die den Metaobjektcode für diese Klassen enthält. Unter anderem wird Metaobjektcode für den Signal- und Slot-Mechanismus, die Laufzeittypinformationen und das dynamische Eigenschaftssystem benötigt.

Stu Mackellar
quelle
warum muss ich nicht explizit schreiben Q_OBJECT::connect(), sondern nur connect()?
mLstudent33
19

Es teilt dem Pre-Compiler einfach mit, dass diese Klasse GUI-Elemente enthält und über das 'moc' ausgeführt werden muss. Sie müssen dies nur Klassen hinzufügen, die den Signal- / Slot-Mechanismus verwenden.
In anderen Klassen wird es jedoch stillschweigend ignoriert - es verlängert nur die Erstellungszeit.

Martin Beckett
quelle
3
Es ist auch falsch, dass Sie es nur für Klassen benötigen, die den Signal- / Slot-Mechanismus verwenden. Das Fehlen von Q_OBJECTBrüchen qobject_castund Selbstbeobachtung. Es kann zu verwirrendem Verhalten führen, daher ist es eine schlechte Idee.
Stellen Sie Monica am
2
Es ist nicht wahr, dass Q_OBJECTin anderen (Nicht- QObject) Klassen "leise" ignoriert wird . Gemäß dem C ++ - Standard wird undefiniertes Verhalten eingeführt, indem mehrere Elementfunktionen und Variablen deklariert werden, die niemals definiert werden. Außerdem wird der Namespace Ihrer Klasse mit bestimmten QObjectMitgliedern verschmutzt . Q_OBJECTZum Beispiel kann a eine nicht verwandte Klasse brechen, die zufällig eine aufgerufene Methode enthält metaObject.
Stellen Sie Monica am
2
Das ist falsch. Obwohl Sie wahrscheinlich die meisten GUI-Klassen mit dem Q_OBJECTMakro ausstatten möchten , ist es durchaus sinnvoll, Nicht-GUI-Klassen mit dem Makro sowie GUI-Klassen ohne das Makro zu haben. Das Makro ist nützlich, aber für GUI-Klassen weder beschränkt noch erforderlich.
Pasbi
9

Der MOC (Meta Object Compiler) konvertiert die im Q_OBJECT-Makro enthaltenen Header-Dateien in C ++ -äquivalenten Quellcode. Es steuert im Wesentlichen den Signal-Slot-Mechanismus und macht ihn für den C ++ - Compiler verständlich

aditya
quelle
2
Das ist falsch: Das Q_OBJECTMakro wird vom Compiler erweitert, dafür wird moc nicht benötigt. Das moc macht nichts mit dem Makro selbst, sondern generiert die Definitionen der Mitgliedsvariablen und -methoden, die das Q_OBJECTMakro deklariert hat .
Stellen Sie Monica am
5

1 Aus der Qt-Dokumentation des Meta-Object-Systems

Das moc-Tool liest eine C ++ - Quelldatei. Wenn eine oder mehrere Klassendeklarationen gefunden werden, die das Makro Q_OBJECT enthalten, wird eine weitere C ++ - Quelldatei erstellt, die den Metaobjektcode für jede dieser Klassen enthält. Diese generierte Quelldatei wird entweder # in die Quelldatei der Klasse aufgenommen oder in der Regel kompiliert und mit der Implementierung der Klasse verknüpft.

2 Aus der Qt-Dokumentation von THE Q_OBJECT

Das Q_OBJECT-Makro muss im privaten Abschnitt einer Klassendefinition erscheinen, die ihre eigenen Signale und Slots deklariert oder andere Dienste verwendet, die vom Metaobjektsystem von Qt bereitgestellt werden.

3 Aus der Qt-Dokumentation von moc

Das moc-Tool liest eine C ++ - Headerdatei. Wenn eine oder mehrere Klassendeklarationen gefunden werden, die das Q_OBJECT-Makro enthalten, wird eine C ++ - Quelldatei erstellt, die den Metaobjektcode für diese Klassen enthält. Unter anderem wird Metaobjektcode für den Signal- und Slot-Mechanismus, die Laufzeittypinformationen und das dynamische Eigenschaftssystem benötigt.

4 Aus der Qt-Dokumentation von Signalen und Slots

Das Q_OBJECT-Makro wird vom Präprozessor erweitert, um mehrere Mitgliedsfunktionen zu deklarieren, die vom moc implementiert werden. Wenn Sie Compilerfehler im Sinne von "undefinierter Verweis auf vtable für LcdNumber" erhalten, haben Sie wahrscheinlich vergessen, den moc auszuführen oder die moc-Ausgabe in den Link-Befehl aufzunehmen.

Bob Zhang
quelle
2

In gcc mit sehen -ESie erweiterte Makros. Dies ist, was Q_OBJECTauf gcc unter Linux erweitert wird. Beachten Sie, dass dies möglicherweise plattformabhängig ist und sich je nach Version von QT ändern kann. Sie sehen, es ist nicht nur ein Tag für den moc-Compiler.

# 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
quelle
0

Das Q_OBJECT-Makro muss im privaten Abschnitt einer Klassendefinition erscheinen, die ihre eigenen Signale und Slots deklariert oder andere Dienste verwendet, die vom Metaobjektsystem von Qt bereitgestellt werden.

Andres
quelle
1
Dies ist irreführend: Das Q_OBJECTMakro muss in jeder Klasse erscheinen, von der abgeleitet wird QObject. Ihr Code wird auf subtile Weise beschädigt, wenn das Makro fehlt, und nur weil es gerade kompiliert wird, ist es nicht in Ordnung.
Stellen Sie Monica am
@KubaOber Haben Sie ein Beispiel für Code, der kompiliert wird, aber nicht funktioniert, wenn das Q_OBJECTMakro fehlt?
Chris
2
Wenn Sie sich die Implementierung von ansehen Q_OBJECT, werden Sie feststellen, dass Zugriffsspezifizierer verwendet werden. Es ist also unerheblich, ob das Makro unter dem private, protectedoder unter den publicBezeichnern angezeigt werden soll - es ist nur eine Konvention, es an die Spitze der Klasse zu setzen.
TrebledJ