Q_OBJECT抛出“对 vtable 的未定义引用”错误 [重复]

Q_OBJECT throwing 'undefined reference to vtable' error [duplicate]

提问人:Donotalo 提问时间:1/23/2011 更新时间:11/25/2016 访问量:69105

问:

我在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_OBJECTQGraphicsItemQ_OBJECT

代码有什么问题?谢谢。

C++ Qt 链接器错误 vtable

评论


答:

141赞 Sergei Tachenov 1/23/2011 #1

这是因为 MOC 生成的单元不包括在链接过程中。或者它可能根本没有生成。我要做的第一件事是将类声明放在单独的头文件中,也许构建系统没有扫描实现文件。

另一种可能性是,有问题的类曾经不属于Qt元对象系统(也就是说,它没有Q_OBJECT,或者可能根本没有继承自QObject),因此需要再次运行qmake才能为MOC创建必要的规则。强制运行 qmake 的最简单方法是对项目文件进行一些无关紧要的更改以更新其时间戳,例如添加然后删除一些空格。或者,如果您使用的是Qt Creator,则只需从项目上下文菜单中选择“运行qmake”。

评论

0赞 Donotalo 1/23/2011
在我的实际实现中,该类在标头和实现文件中是分开的。那里也存在错误。
0赞 Sergei Tachenov 1/23/2011
@Donotalo,MOC 是否在编译过程中运行?你试过清理和重建吗?
0赞 Troubadour 1/23/2011
@Sergey Tachenov:你认为这个单元可能根本不是由生成的,这是这里的问题,因为类声明不在标头中。moc
4赞 Donotalo 1/24/2011
谢谢你的想法。我清理并重建了这个项目,但它没有用。然后我编辑了 *.pro 文件并重新编译。它解决了问题!
4赞 Alex Hendren 11/6/2013
答案恰到好处 - 涵盖了我的情况,该对象最初不属于 Qt 元对象系统。不过,简单地编辑文件对我不起作用。我必须删除我的 .user 文件并按照@Donotalo建议触摸 *.pro 文件。再次运行qMake后,生活又恢复了美好。
8赞 Stephen Chu 1/23/2011 #2

将Q_OBJECT类放在单独的文件中。即每个类一个 .h 和一个.cpp。Qt的元对象宏在这方面有点挑剔。

此外,您可以将QGraphicsObject用于您的目的。为您节省一些时间。

编辑:我看到您正在使用Creator。在“新建文件”或“项目”中使用其“新建C++类”功能以“正确的方式”创建文件:)

评论

0赞 Sunny127 1/4/2017
将 .h .cpp 文件放在单独的文件夹中。
4赞 serge_gubenko 1/23/2011 #3

有几件事需要注意:

  1. 在专业文件中添加 QT += gui
  2. 确保仅在头文件中定义 QObject 派生类(编辑:正如 Troubadour 所指出的,这不是必需的)
  3. 将 Q_INTERFACES(QGraphicsItem) 添加到 T 类的声明中

下面是一个示例:

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

我尝试编译上面的代码,但没有问题。

希望这有帮助,问候

评论

0赞 Troubadour 1/23/2011
无需仅在标头中定义 QObject 子类。这只是最常见的方法。有关详细信息,请参阅我的答案。
0赞 iizno 3/25/2013
“在您的专业文件中添加 QT += gui”这简直救了我。谢谢。
27赞 Troubadour 1/23/2011 #4

如果要在源文件中定义子类,则需要添加以下行QObject

#include "file.moc"

在类定义之后的某个时间点,源文件的名称为 File.cpp。当然,您需要重新运行,以便将要运行的相应规则添加到 Makefile 中。qmakemoc

只有在头文件中,类定义中是否存在 才会被调用。如果它是源文件,则需要强制使用此额外的行。Q_OBJECTmocmoc

我敢肯定以前有人问过类似的问题,但我找不到。

评论

0赞 osirisgothra 12/15/2013
太好了,几天来我一直在寻找一种方法来做到这一点,但不知道这一点,他们没有在 QObject 文档中告诉你这样的东西。
6赞 Tuukka Lindroos 1/24/2011 #5

以下是添加了其他问题中提供的所有修复程序的工作代码(尝试了干净编译,这些修复程序有所帮助):

#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

评论

0赞 edin-m 6/13/2015
对我来说,这很有帮助,因为 QObject 必须像这里一样排在第一位。