webentwicklung-frage-antwort-db.com.de

Q_OBJECT wirft den Fehler 'undefinierter Verweis auf vtable' auf

Ich verwende Qt Creator 2.0.1 mit Qt 4.7.0 (32 Bit) unter Windows 7 Ultimate 32 Bit.

Betrachten Sie den folgenden Code, der das Minimum darstellt, um den Fehler zu erzeugen:

class T : public QObject, public QGraphicsItem
{
    Q_OBJECT

public:
    T() {}

    QRectF      boundingRect() const {return QRectF();}
    void        Paint(QPainter *Painter, const QStyleOptionGraphicsItem *option,
                      QWidget *widget) {}
};

int main()
{
    T t;
    return 0;
}

Das obige Codefragment verursacht die folgenden Linker-Fehler:

In der Funktion 'T':

undefinierter Verweis auf `vtable for T '

undefinierter Verweis auf `vtable for T '

In der Funktion ~ T:

undefinierter Verweis auf `vtable for T '

undefinierter Verweis auf `vtable for T '

Wenn ich die Zeile auskommentiere, die Q_OBJECT Enthält, wird sie korrekt kompiliert. Ich brauche ein Signal und Slots mit QGraphicsItem, also brauche ich Q_OBJECT.

Was ist los mit dem Code? Vielen Dank.

61
Donotalo

Dies liegt daran, dass die von MOC generierte Einheit nicht in den Verknüpfungsprozess einbezogen wird. Oder vielleicht wird es gar nicht erzeugt. Das erste, was ich tun würde, ist, die Klassendeklaration in einer separaten Header-Datei abzulegen. Vielleicht scannt das Build-System keine Implementierungsdateien.

Eine andere Möglichkeit besteht darin, dass die betreffende Klasse nicht zum Qt-Metaobjektsystem gehörte (dh, sie hatte kein Q_OBJECT oder erbte möglicherweise überhaupt kein QObject). Daher muss qmake erneut ausgeführt werden, um das zu erstellen notwendige Regeln für MOC. Die einfachste Möglichkeit, die Ausführung von qmake zu erzwingen, besteht darin, geringfügige Änderungen an der Projektdatei vorzunehmen, um den Zeitstempel zu aktualisieren, z. B. Leerzeichen hinzuzufügen und anschließend zu entfernen. Wenn Sie Qt Creator verwenden, wählen Sie einfach im Kontextmenü des Projekts die Option "qmake ausführen".

121
Sergei Tachenov

Wenn Sie eine Unterklasse QObject in einer Quelldatei definieren möchten, müssen Sie die Zeile hinzufügen

#include "file.moc"

irgendwann nach Ihrer Klassendefinition war der Name der Quelldatei file.cpp. Sie müssen qmake natürlich erneut ausführen, damit die entsprechende Regel zum Ausführen von moc zum Makefile hinzugefügt wird.

Nur wenn in einer Header-Datei das Vorhandensein von Q_OBJECT in einer Klassendefinition bewirkt, dass moc aufgerufen wird. Wenn es sich um eine Quelldatei handelt, benötigen Sie diese zusätzliche Zeile, um die Verwendung von moc zu erzwingen.

Ich bin sicher, dass eine ähnliche Frage schon einmal gestellt wurde, aber ich konnte sie nicht finden.

23
Troubadour

Platzieren Sie Ihre Q_OBJECT-Klassen in separaten Dateien. Das ist eine .h und eine .cpp für jede Klasse. Qts Meta-Objekt-Makros sind in dieser Hinsicht ziemlich wählerisch.

Sie können auch QGraphicsObject für Ihren Zweck verwenden. Spart Ihnen dort etwas Zeit.

Bearbeiten: Ich sehe, dass Sie Creator verwenden. Verwenden Sie die Funktion New C++ Class in New File oder Project, um die Datei "richtig" zu erstellen :)

8
Stephen Chu

Hier wird Arbeitscode mit allen in anderen Fragen bereitgestellten Fixes hinzugefügt (Versuchtes sauberes Kompilieren und diese Fixes helfen):

#include <QGraphicsItem>

class T : public QObject, public QGraphicsItem
{
    Q_OBJECT
    Q_INTERFACES(QGraphicsItem) //Required.

public:
    T() {}
    QRectF      boundingRect() const {return QRectF();}
    void        Paint(QPainter *Painter, const QStyleOptionGraphicsItem *option,
                      QWidget *widget) {}
};

int main(int argc, char *argv[])
{
    T *t = new T;
    return 0;
}

#include "main.moc" // Required.

Also wirklicher Dank an Troubadour und serge_gubenko

6
Tuukka Lindroos

es gibt ein paar Dinge zu sehen:

  1. Fügen Sie QT + = gui in Ihre Pro-Datei ein
  2. Stellen Sie sicher, dass Sie Ihre von QObject abgeleiteten Klassen nur in Ihren Header-Dateien definieren (Bearbeiten: Wie Troubadour feststellte, ist dies nicht erforderlich).
  3. Fügen Sie der Deklaration Ihrer T-Klasse Q_INTERFACES (QGraphicsItem) hinzu

unten ist ein Beispiel:

t.h:

class T : public QObject, public QGraphicsItem
{
    Q_OBJECT
    Q_INTERFACES(QGraphicsItem)

public:
    T();
    QRectF boundingRect() const;
    void Paint(QPainter *Painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
};

t.cpp:

T::T() {}

QRectF T::boundingRect() const
{
    return QRectF();
}

void T::Paint(QPainter *Painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    Q_UNUSED(Painter);
    Q_UNUSED(option);
    Q_UNUSED(widget);
}

Ich habe versucht, den obigen Code zu kompilieren und hatte keine Probleme damit.

hoffe das hilft, grüße

4
serge_gubenko