C++ 使用CONFIG+;构建Qt应用程序“原因”;未定义对vtable的引用;错误

C++ 使用CONFIG+;构建Qt应用程序“原因”;未定义对vtable的引用;错误,c++,linux,qt,gcc,qt-creator,C++,Linux,Qt,Gcc,Qt Creator,编辑:我对这篇文章进行了大量的编辑,以将这个项目精简到最基本的部分。我还添加了一个,包括本文中未引用的文件 我有一个QtCreator项目(qmake,Qt5.2.0,Creator 3.0.0),它使用子目录模板。有三个子项目: 体育场-配置为TEMPLATE=lib和CONFIG+=staticlib的库 足球-配置为TEMPLATE=lib和CONFIG+=staticlib并使用字段的库 服务器-使用体育场和足球库的QML应用程序 我正在Windows8.1(MSVC2012)和Lin

编辑:我对这篇文章进行了大量的编辑,以将这个项目精简到最基本的部分。我还添加了一个,包括本文中未引用的文件


我有一个QtCreator项目(qmake,Qt5.2.0,Creator 3.0.0),它使用
子目录
模板。有三个子项目:

  • 体育场-配置为
    TEMPLATE=lib
    CONFIG+=staticlib
    的库
  • 足球-配置为
    TEMPLATE=lib
    CONFIG+=staticlib
    并使用
    字段的库
  • 服务器-使用体育场和足球库的QML应用程序
  • 我正在Windows8.1(MSVC2012)和Linux(GCC4.8.1)上构建这个应用程序它在Windows上正常工作,但Linux版本的行为异常

    我得到的错误如下所示:

    undefined reference to 'vtable for Stadium::Engine'
    
    #ifndef STADIUM_ENGINE_H
    #define STADIUM_ENGINE_H
    
    #include <QObject>
    
    namespace Stadium {
    
    class Engine : public QObject
    {
        Q_OBJECT
    
    public slots:
        virtual void executeCommand() = 0;
    
    };
    
    } // namespace Stadium
    
    #endif // STADIUM_ENGINE_H
    
    我已将此项目重写为一组显示错误的裸文件。您可以在Github上找到它,网址:。请随意克隆它并亲自查看所有错误。
    661441c
    commit解决了问题,而
    09836f9
    commit包含错误

    Stadium Engine.h文件是一个抽象类。看起来是这样的:

    undefined reference to 'vtable for Stadium::Engine'
    
    #ifndef STADIUM_ENGINE_H
    #define STADIUM_ENGINE_H
    
    #include <QObject>
    
    namespace Stadium {
    
    class Engine : public QObject
    {
        Q_OBJECT
    
    public slots:
        virtual void executeCommand() = 0;
    
    };
    
    } // namespace Stadium
    
    #endif // STADIUM_ENGINE_H
    
    我尝试过清理、重新运行qmake、删除构建目录和重建。在Linux中构建此项目的唯一方法是删除Stadium库的.pro文件中的
    CONFIG+=staticlib
    行(当然还有Game.pro中相应的
    else:unix:PRE\u TARGETDEPS+=$$OUT\u PWD/./Stadium/libstadium.a
    行)。这将成功构建项目,并且运行时不会出现问题。但我不明白为什么。我也不明白为什么构造函数定义在哪里很重要


    有什么想法吗?

    您已经内联了虚拟析构函数。
    这有时会导致问题。

    尝试在.cpp文件中实现析构函数。我还将从析构函数的声明中删除
    =0

    我看不到您在哪里运行moc编译器。moc创建一个文件,用于解析QObject派生类的其他内容

    如果moc正在运行,那么您的命名空间可能就是问题所在。众所周知,moc不能很好地处理名称空间。我喜欢名称空间,但Qt在人们开始到处使用它们之前就已经存在了

    如果该类不是绝对必需的,那么移除Q_对象并从QObject派生是另一种解决方案


    另一种可能是您的makefile已过时。在这种情况下,您需要强制运行qmake以确保它们正确刷新。

    您可以查看以下其他问题:

    我试着把你的引擎代码编译成一个静态库,然后从一个应用程序链接,但是当没有定义虚拟纯析构函数时,我遇到了一个错误(正如预期的那样)。如果没有定义虚拟析构函数,则无法实例化任何派生类


    无论如何,您的类继承自QObject,它已经声明并实现了一个非纯虚拟析构函数。纯虚拟析构函数有用吗

    好吧,我找到了解决办法。我有三个不同的问题,当更改时,会清除vtable错误。不幸的是,我不知道为什么后两个改变是必要的

    1.派生类中的Q_对象 继承上述Stadium::Engine类的类内部有一个额外的Q_对象。当我删除派生类中的第二个Q_对象时,其中一个vtable错误消失了

    2.引擎构造器 我不明白为什么,但是当派生类在CPP文件中定义构造函数时,它会给出
    vtable
    错误。在标题中定义(在类描述中)时,它可以正常工作。构造函数中没有任何内容(
    DerivedEngine(){}
    )。我不明白这有什么关系

    3.定义构造函数和虚拟析构函数 要求构造函数和析构函数都在纯抽象类中定义。我不明白为什么。我在类定义之外的标题中添加了以下行:

    inline Stadium::Engine::Engine() {}
    inline Stadium::Engine::~Engine() {}
    

    这仍然困扰着我。为什么这些改变是必要的?为什么这只发生在gcc/Linux上?这肯定是一个Qt错误,对吗?

    答案非常简单:库的链接顺序错误。

    我查看了调用链接器的命令(链接器错误正上方):

    我还研究了代码:Football子项目指的是Stadium子项目,因此库的顺序是错误的,例如,请参见的公认答案以获取解释

    事实上,如果我交换Server.pro文件中的两个库(源自commit
    09836f9
    ,为简洁起见,删除了与win32相关的详细信息):

    现在,命令行如下所示:

    g++ [...] -lFootball [...] -lStadium
    

    它在我的Linux机器上编译并运行得很好。

    内联析构函数是某个人的建议,他认为它可能会有所帮助。删除它不会影响错误。(编辑时间用完):不幸的是,将析构函数删除到CPP文件(或完全删除)不会改变任何内容。我也试着让它非纯,但没用。当你需要运行qmake时,我看到了这一点again@paulm,是的,但它似乎不起作用。我开始怀疑在构建过程中有一个bug。显示从中继承的代码Engine@paulm,您暗示的建议至少部分正确。:)从引擎继承的代码有一个额外的Q_对象宏(不必要,因为继承的类已经有了这个宏)。奇怪的是,构建过程从未在继承的类中标记错误。我仍在努力弄清楚,在我尝试过的15件事情中,哪些是我帮助过的,但我很快会发布解决方案
    g++ [...] -lStadium [...] -lFootball 
    
    [...]
    
    SOURCES += main.cpp
    
    LIBS += -L$$OUT_PWD/../Football/ -lFootball
    INCLUDEPATH += $$PWD/../Football
    DEPENDPATH += $$PWD/../Football
    PRE_TARGETDEPS += $$OUT_PWD/../Football/libFootball.a
    
    LIBS += -L$$OUT_PWD/../Stadium/ -lStadium
    INCLUDEPATH += $$PWD/../Stadium
    DEPENDPATH += $$PWD/../Stadium
    PRE_TARGETDEPS += $$OUT_PWD/../Stadium/libStadium.a
    
    g++ [...] -lFootball [...] -lStadium