web-dev-qa-db-ja.com

「vtableへの未定義の参照」エラーをスローするQ_OBJECT

Windows 7 Ultimate 32ビットでQt Creator 2.0.1とQt 4.7.0(32ビット)を使用しています。

エラーを生成するための最小のコードである次のコードを検討してください。

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;
}

上記のコードフラグメントにより、次のリンカーエラーが発生します。

関数「T」:

「vtable for T」への未定義の参照

「vtable for T」への未定義の参照

関数 `〜T 'で:

「vtable for T」への未定義の参照

「vtable for T」への未定義の参照

Q_OBJECTを含む行をコメントアウトすると、正常にコンパイルされます。 QGraphicsItemを含む信号とスロットが必要なので、Q_OBJECTが必要です。

コードの何が問題になっていますか?ありがとう。

61
Donotalo

これは、MOCによって生成されたユニットがリンクプロセスに含まれていないためです。または、まったく生成されない場合もあります。最初に行うことは、クラス宣言を別のヘッダーファイルに配置することです。おそらく、ビルドシステムは実装ファイルをスキャンしていません。

別の可能性は、問題のクラスがかつてQtメタオブジェクトシステムに属していなかった(つまり、Q_OBJECTを持たなかった、またはQObjectをまったく継承しなかった)ため、qmakeを作成するために再度実行する必要があることです。 MOCに必要なルール。 qmakeを強制的に実行する最も簡単な方法は、空白を追加してから削除するなど、プロジェクトファイルにわずかな変更を加えてタイムスタンプを更新することです。または、Qt Creatorを使用している場合は、プロジェクトコンテキストメニューから[Run qmake]を選択するだけです。

121
Sergei Tachenov

ソースファイルでQObjectサブクラスを定義する場合は、次の行を追加する必要があります

#include "file.moc"

ソースファイルの名前がfile.cppであるクラス定義の後のある時点。もちろん、qmakeを再実行して、mocを実行する適切なルールをMakefileに追加する必要があります。

ヘッダーファイル内でクラス定義にQ_OBJECTが存在する場合にのみ、mocが呼び出されます。ソースファイルの場合、mocを強制的に使用するには、この追加行が必要です。

同様の質問が以前に聞かれたことは確かですが、それを見つけることができませんでした。

23
Troubadour

Q_OBJECTクラスを個別のファイルに配置します。それは、各クラスに対して1つの.hと1つの.cppです。 Qtのメタオブジェクトマクロは、この点で多少うるさいです。

また、目的に QGraphicsObject を使用できます。そこで時間を節約できます。

編集:Creatorを使用しているようです。 「正しい方法」でファイルを作成するには、新しいファイルまたはプロジェクトでその新しいC++クラス関数を使用します:)

8
Stephen Chu

以下は、他の質問で提供されたすべての修正とともに追加された作業コードです(クリーンコンパイルを試行し、これらの修正が役立ちます)。

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

トルバドールとserge_gubenkoへの実際のクレジット

6
Tuukka Lindroos

見るべきことがいくつかあります:

  1. QT + = guiをプロファイルに追加します
  2. ヘッダーファイルのみでQObject派生クラスを定義してください(編集:Troubadourが述べたように、これは必須ではありません)
  3. Tクラスの宣言にQ_INTERFACES(QGraphicsItem)を追加します

以下に例を示します。

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);
}

上記のコードをコンパイルしてみましたが、問題はありませんでした。

よろしくお願いします

4
serge_gubenko