Das ist meine Kopfzeile:
#ifndef BARELYSOCKET_H
#define BARELYSOCKET_H
#include <QObject>
//! The First Draw of the BarelySocket!
class BarelySocket: public QObject
{
Q_OBJECT
public:
BarelySocket();
public slots:
void sendMessage(Message aMessage);
signals:
void reciveMessage(Message aMessage);
private:
// QVector<Message> reciveMessages;
};
#endif // BARELYSOCKET_H
Das ist meine Klasse:
#include <QTGui>
#include <QObject>
#include "type.h"
#include "client.h"
#include "server.h"
#include "barelysocket.h"
BarelySocket::BarelySocket()
{
//this->reciveMessages.clear();
qDebug("BarelySocket::BarelySocket()");
}
void BarelySocket::sendMessage(Message aMessage)
{
}
void BarelySocket::reciveMessage(Message aMessage)
{
}
Ich erhalte einen Linker-Fehler:
undefined reference to 'vtable for BarelySocket'
Message
ist eine komplexe struct
, aber selbst die Verwendung von int
hat Nicht behoben.Wenn Sie dem Makro Q_OBJECT einen neuen Aufruf hinzufügen, müssen Sie qmake erneut ausführen. Das Problem mit der Vtables, auf das Sie sich beziehen, hängt direkt damit zusammen.
Führen Sie einfach qmake aus und Sie sollten sich darauf einstellen, dass in Ihrem Code keine anderen Probleme vorhanden sind.
Ich habe viele Wege gesehen, um das Problem zu lösen, aber es gibt keine Erklärung dafür, warum es passiert.
Wenn der Compiler eine Klasse mit virtuellen Funktionen (direkt deklariert oder geerbt) sieht, muss er eine vtable für diese Klasse generieren. Da Klassen im Allgemeinen in Kopfzeilen definiert sind (und daher in mehreren Übersetzungseinheiten erscheinen), stellt sich die Frage, wo die vtable platziert werden soll.
Im Allgemeinen kann das Problem gelöst werden, indem die vtable in jedem TU generiert wird, in dem die Klasse definiert ist, und der Linker dann Duplikate entfernen soll. Da die Klassendefinitionen bei jedem Vorkommen durch den ODR gleich sein müssen, ist dies sicher. Es verlangsamt jedoch auch die Kompilierung, bläst Objektdateien auf und erfordert, dass der Linker mehr Arbeit erledigt.
Zur Optimierung wählen Compiler daher, wenn möglich, ein bestimmtes TU, um die vtable zu platzieren. In der üblichen C++ - ABI ist dies TU das, bei dem die key-Funktion von Die Klasse ist in implementiert, wobei die Schlüsselfunktion die erste virtuelle Memberfunktion ist, die in der Klasse deklariert, jedoch nicht definiert ist.
Bei Qt-Klassen beginnen sie normalerweise mit dem Makro Q_OBJECT, und dieses Makro enthält die Deklaration
virtual const QMetaObject *metaObject() const;
da dies die erste virtuelle Funktion im Makro ist, wird sie im Allgemeinen die erste virtuelle Funktion der Klasse und somit ihre Schlüsselfunktion sein. Der Compiler gibt daher die vtable in den meisten TUs nicht aus, nur die, die metaObject
implementiert. Die Implementierung dieser Funktion wird automatisch von moc
geschrieben, wenn sie den Header verarbeitet. Daher muss moc
Ihren Header verarbeiten, um eine neue .cpp-Datei zu generieren, und dann die .cpp-Datei in Ihre Kompilierung einschließen.
Wenn Sie also einen neuen Header haben, der eine von QObject
abgeleitete Klasse definiert, müssen Sie qmake
erneut ausführen, damit Ihre Makefiles aktualisiert werden, um moc
im neuen Header auszuführen und die resultierende .cpp-Datei zu kompilieren.
Ich bin auf diesen Fehler gestoßen, nachdem ich eine kleine Klasse in einer kleinen "main.cpp" -Datei erstellt hatte, die ich erstellt hatte, um etwas zu testen.
Nachdem ich mich etwa eine Stunde lang damit beschäftigt hatte, diese Klasse aus main.cpp in eine eigenständige hpp-Datei zu verschieben, die .pro-Datei (Projektdatei) zu aktualisieren und das Projekt dann perfekt zu bauen. Das war vielleicht nicht das Thema, aber ich dachte mir, dass es ohnehin nützliche Informationen wäre.
Aus Erfahrung: Oft hilft ein qmake && clean && make ..__ Ich persönlich merke, dass manchmal die Veränderung/Zwischenspeicherungseffekte/Was auch immer-ich-weiß-nicht-xxxxx. Ich kann nicht sagen warum, aber es ist das erste, was ich mache, wenn ich auf einen solchen Fehler stoße.
Übrigens Es gibt einen Tippfehler bei> recive <
Sie haben vergessen, den QObject-Konstruktor in Ihrem Konstruktor (in der Initialisierungsliste) aufzurufen. (Der Fehler wird jedoch nicht behoben.)
Ich habe bei Build-Protokollen festgestellt, dass Moc nicht aufgerufen wurde. Sauber alles hat nicht geholfen. Also entfernte ich .pro.user, starte IDE neu und es gelang mir.
Wenn Sie eine Klasse von QOBject ableiten (und das Makro Q_OBJECT verwenden), vergessen Sie nicht, sowohl die Konstruktor- als auch die Destruktor-Klasse zu definieren und zu erstellen. Es reicht nicht aus, den Compiler-Standardkonstruktor/-destruktor zu verwenden. Die Ratschläge zum Reinigen/Ausführen von qmake (und zum Entfernen Ihrer moc_-Dateien) gelten weiterhin ... Dies hat mein ähnliches Problem behoben.
Signale dürfen keine Implementierung haben (dies wird von Qt generiert). Entfernen Sie die reciveMessage
-Implementierung aus Ihrer CPP-Datei. Dies kann Ihr Problem lösen.
Eine andere Sache, die ich gesehen habe: Da die BarelySocket
-Klasse von QObject erbt, muss sie einen virtuellen Destruktor haben, um Probleme während der Zerstörung zu vermeiden. Dies muss für alle Klassen erfolgen, die von einer anderen Klasse erben.
Ich habe mit diesen Fehlerstunden zu kämpfen. Es wurde gelöst, indem die .cpp- und .h-Datei in einen separaten Ordner (!!) ..__ gestellt wurde. Dann wurde der Ordner der .pro-Datei hinzugefügt: INCLUDEPATH + = $$ {_ PRO_FILE_PWD _} /../ MyClasses/CMyClassWidget
und fügte dann die .cpp- und .h-Datei hinzu.
Ich habe einen anderen Grund gefunden, warum Sie dies sehen könnten - da qmake
Ihre Klassendateien durchläuft, wenn Sie sie auf eine nicht standardmäßige Weise geändert haben, erhalten Sie möglicherweise diesen Fehler. In meinem Fall hatte ich ein benutzerdefiniertes Dialogfeld, das von QDialog übernommen wurde, aber ich wollte nur, dass es kompiliert und ausgeführt wird, wenn Sie für Linux, nicht für Windows oder OSX, erstellen. Ich habe gerade #ifdef __linux__
die Klasse rausgeschmissen, also nicht kompiliert, aber in Linux wurde qmake
definiert, obwohl __linux__
definiert wurde.