wake-up-neo.com

Qt Linker Error: "undefinierter Verweis auf vtable"

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'
  • Dies bedeutet, dass ich eine virtuelle Methode nicht implementiert habe. Es gibt aber keine virtuellen Methoden in meiner Klasse.
  • Ich kommentierte den Vektor aus und dachte, dass dies die Ursache war, aber der -Fehler ging nicht weg.
  • Die Message ist eine komplexe struct, aber selbst die Verwendung von int hat Nicht behoben.
56
Thomas

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.

127
Michael

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.

33
Sebastian Redl

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.

13
David

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.)

10
Ronny Brendel

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.

4
lstipakov

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.

2
Pete

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.

2

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.

1
Sunny127

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.

0
Preston