Es gibt zahlreiche Threads zu diesem Thema. Keiner scheint meiner Rechnung zu entsprechen. Ich bekomme folgende Linkfehler in meinem Code:
%Vor%Es sollte etwas Offensichtliches sein als - eine fehlende vtable bedeutet normalerweise, dass die erste nichtlineare virtuelle Elementfunktion keine Definition hat. Ich sehe jedoch nicht, was mir fehlt:
Ich habe diese Klassenerklärung in MSFSPlugin.h
:
Dann in MSFSPlugin.cpp
, ich habe folgendes:
Es folgen Definitionen:
%Vor%Kurz gesagt, ich glaube nicht, dass ich eine nichtlineare virtuelle Memberfunktionsdefinition vermisse. Ich benutze:
%Vor%Zusätzliche Informationen:
In meinem moc_MSFSPlugin.cpp
sehe ich nicht den automatisch generierten Q_OBJECT
Code für die Klasse MSFSPlugin::MSFSPluginImpl
, der indirekt (via QThread) von QObject
abgeleitet wird. Genauer gesagt, ich sehe keinen Code, der für das Signal generiert wurde, das in dieser Klasse deklariert ist ( loadDirectoryFinished
). Könnte das das Problem sein?
EDIT 1:
Der Fehler verschwindet, wenn ich Q_OBJECT
aus der Deklaration von MSFSPlugin::MSFSPluginImpl
auskommentiere, aber dann verliere ich die Signalfunktionalität.
EDIT 2: Ich sehe, moc arbeitet nur auf Header-Dateien. Könnte dies mit der Tatsache zusammenhängen, dass meine abgeleitete QObject-Klasse & amp; in einer CPP-Datei definiert?
Angenommen, es handelt sich um qmake
.
Q_OBJECT
in der Definition aller QObject
-abgeleiteten Klassen vorhanden ist. QObject
-dedived-Klassen in Ihren Header-Dateien only deklarieren. HEADERS=
-Liste aufgeführt sind. qmake
jedes Mal aus, wenn Sie Q_OBJECT
zu einer Ihrer Klassen hinzufügen oder Ihre .pro
-Datei ändern. EDIT 1: Der Fehler verschwindet, wenn ich Q_OBJECT aus der Deklaration von MSFSPlugin :: MSFSPluginImpl auskommentiere, aber dann verliere ich die Signalfunktionalität.
Ja. Q_OBJECT
wird benötigt, um Signale, Slots, Invokabeln, qobject_cast
, Übersetzungen, Eigenschaften, Aufzählungen und Methoden introspection zu deklarieren.
Die goldene Regel # 1 kommt von der Tatsache, dass ohne Q_OBJECT
du kannst Sachen wie qobject_cast
in deiner Klasse nicht benutzen; wenn Sie (selbst indirekt) Introspektionsfunktionen verwenden, zum Beispiel um eine Objekthierarchie zu debuggen oder um alle aktiven Verbindungen zu einem Objekt abzulegen , dann haben die Objekte Ihrer Klasse das echte Klassenname angezeigt (und nicht der der Oberklasse); usw.
Q_OBJECT
macht zwei Dinge:
moc
hinzuzufügen, deren Aufgabe es ist, zusätzlichen Code für die Klasse zu generieren. Dieser Code bietet alle oben aufgeführten Funktionen; qt_metacall()
und metaObject()
. moc
generiert die Implementierung für diese virtuellen Dateien. Der Fehler, den Sie erhalten, ist das typische Symptom der Deklaration der virtuellen Dateien (weil das Makro in Ihrem Code erweitert wurde), aber moc
wurde nicht ausgeführt, Sie hatten einige nicht implementierte virtuelle Dateien, die die Verknüpfung fehlschlagen lassen.
Mit gcc und GNU ld erhalten Sie einen noch kryptischeren Fehler, etwa undefined reference to vtable for ClassName
. Wenn Sie solche Fehler googlen, erfahren Sie sofort, wie Sie das Problem lösen können.
EDIT 2: Ich sehe, dass moc nur auf Header-Dateien operiert. Könnte dies mit der Tatsache zusammenhängen, dass meine abgeleitete QObject-Klasse & amp; in einer CPP-Datei definiert?
Die Frage lautet also: Warum wurde moc
nicht in einer Datei ausgeführt, die eine Definition einer Klasse mit dem Makro Q_OBJECT
enthält?
Wenn wir qmake
verwenden, um Ihre Makefiles zu erzeugen, dann wird qmake alle Header-Dateien durchsuchen, die in der HEADERS
-Variable aufgelistet sind. Wenn ein Header eine Klassendefinition mit dem Makro Q_OBJECT
enthält, gibt er auch Anweisungen aus (im Makefile), um moc
über diesen Header auszuführen, kompiliert moc
's Ausgabe und verknüpft das resultierende Objekt in der Endziel.
Und wir haben die Regeln # 2, # 3, # 4 genau hier.
# 2 sagt uns, dass wir Q_OBJECT
classes in die Header setzen sollen; und das liegt daran, dass HEADERS
Header, nicht Quellen auflistet.
# 3 sagt uns, dass wir alle Header in die HEADERS
Liste schreiben sollen. Das liegt natürlich daran, dass, wenn ein Header, der Q_OBJECT
enthält, nicht in dieser Liste enthalten ist, qmake
ihn nicht finden und die Regeln ausgeben wird. (Für Header, die keine QObject-Unterklassen enthalten, ist dies zwar nicht unbedingt erforderlich, aber es ist ratsam, jeden Header dort einzufügen, um keine zu vergessen.)
# 4 sagt uns, qmake
jedesmal neu zu starten, wenn wir Q_OBJECT
hinzufügen oder die .pro
-Datei modifizieren. Der Grund für den ersten Teil der Regel ist, dass wenn qmake
bereits einen Header gescannt hat und keine Q_OBJECT
gefunden hat, keine Regeln im Makefile ausgegeben wurden. Aber das Hinzufügen von Q_OBJECT
benötigt auch diese Regeln; Daher brauchen wir qmake
, um die Header neu zu scannen, und genau das ist es, was qmake
wieder tut.
Der gleiche Grund liegt vor, wenn .pro
geändert wird (zum Beispiel wenn mehr Header hinzugefügt werden - vielleicht mit Q_OBJECT
unter HEADERS
).
Wenn Sie ein GNU-ähnliches make
verwenden, gibt qmake
eine spezielle Regel aus, die make
anweist, qmake
erneut auszuführen und dann das Makefile neu zu starten, wenn .pro
wird nach dem Makefile geändert. Aus diesem Grund müssen Sie in der Regel unter UNIX qmake
nicht manuell erneut ausführen, wenn Sie Ihre .pro
ändern. Wenn Sie nur make
ausführen, wird auch qmake
erneut ausgeführt. Aber das funktioniert nicht überall .
Ist es also unmöglich, eine Klassendefinition mit Q_OBJECT
in einer .cpp
-Datei zu haben?
Nein, das ist durchaus möglich , erfordert jedoch die Verwendung eines irgendwie undokumentierten Features qmake
. Der Trick besteht darin, eine Zeile wie folgt hinzuzufügen:
am Ende der Datei foobar.cpp
, Datei, die eine oder mehrere Klassendefinitionen mit Q_OBJECT
enthält.
qmake
findet diese spezielle Inklusion und generiert eine Regel für moc
, um foobar.moc
zu erstellen, die dann von .cpp
mit aufgenommen und damit zusammen kompiliert wird. (Daher wird es keine zusätzlichen Regeln geben, um foobar.moc
zu kompilieren oder das Ergebnis zu verknüpfen.)
EDIT 1: Der Fehler verschwindet, wenn ich Q_OBJECT aus der Deklaration von MSFSPlugin :: MSFSPluginImpl auskommentiere, aber dann verliere ich die Signalfunktionalität.
Ja, das Makro Q_OBJECT ist für Signale, Steckplätze, Eigenschaften usw. erforderlich.
EDIT 2: Ich sehe, dass moc nur auf Header-Dateien operiert. Könnte dies mit der Tatsache zusammenhängen, dass meine abgeleitete QObject-Klasse & amp; in einer CPP-Datei definiert?
Ja und nein. Ich werde es erklären ..
Normalerweise wird es beim Schreiben durch Trennung gelöst, aber es ist auch möglich, die MOC-Datei nach Ihrer Klassendefinition einzufügen, damit es funktioniert, aber Sie müssen daran denken, nicht mehr als eins einzufügen, um seltsame Konsequenzen zu vermeiden .
Daher könnten Sie in Ihrem Fall eine Datei MSFSPlugin_p.h
oder MSFSPluginImpl.h
für den Implementierungskopf erstellen.
Übrigens ist es eine schlechte Idee, pimpl zu schützen. Das Pimpl-Idiom bedeutet private Implementierung, nicht geschützt.