【问题标题】:Q_OBJECT throwing 'undefined reference to vtable' error [duplicate]Q_OBJECT 抛出“未定义的 vtable 引用”错误 [重复]
【发布时间】:2011-06-14 01:01:32
【问题描述】:

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

代码有什么问题?谢谢。

【问题讨论】:

    标签: c++ qt linker-errors vtable


    【解决方案1】:

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

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

    【讨论】:

    • 在我的实际实现中,类在头文件和实现文件中是分开的。那里也存在错误。
    • @Donotalo,MOC 是否在编译期间运行?你试过清理和重建吗?
    • @Sergey Tachenov:您关于单元可能不是由moc 生成的建议是这里的问题,因为类声明不在标题中。
    • 感谢您的想法。我清理并重建了项目,但它没有用。然后我编辑了 *.pro 文件并重新编译。它解决了问题!
    • Spot on answer - 涵盖了我的情况,即对象最初不属于 Qt 元对象系统。不过,简单地编辑文件对我不起作用。我必须删除我的 .user 文件并按照@Donotalo 的建议触摸 *.pro 文件。再次运行 qMake 后,生活再次美好。
    【解决方案2】:

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

    #include "file.moc"
    

    在类定义之后的某个时刻,源文件的名称是 file.cpp。当然,您需要重新运行 qmake,以便将运行 moc 的相应规则添加到 Makefile。

    仅当在头文件中出现Q_OBJECT 时,类定义中才会调用moc。如果它是一个源文件,你需要这个额外的行来强制使用moc

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

    【讨论】:

    • +1 太棒了,我不知道这个!
    • 太好了,我这几天一直在寻找一种方法来做到这一点,但没有意识到这一点,他们不会在 QObject 文档中告诉你这样的东西。
    【解决方案3】:

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

    此外,您可以使用QGraphicsObject 来实现您的目的。为您节省一些时间。

    编辑:我看到您正在使用 Creator。在 New File 或 Project 中使用其 New C++ Class 函数以“正确的方式”创建文件:)

    【讨论】:

    • 将 .h .cpp 文件放在单独的文件夹中。
    【解决方案4】:

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

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

    真正归功于 Troubadour 和 serge_gubenko

    【讨论】:

    • 对我来说这很有帮助,因为 QObject 必须像这里一样排在第一位。
    【解决方案5】:

    有几件事要看:

    1. 在您的 pro 文件中添加 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);
    }
    

    我已经尝试编译上面的代码,没有遇到任何问题。

    希望这会有所帮助,问候

    【讨论】:

    • 没有必要只在标题中定义 QObject 子类。这只是最常见的做法。详情见我的回答。
    • “在你的 pro 文件中添加 QT += gui”这只是救了我。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-27
    • 2011-02-03
    • 2014-06-04
    • 1970-01-01
    相关资源
    最近更新 更多