C++ Qt 链接器错误:“对 vtable 的未定义引用”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2555816/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 23:54:03  来源:igfitidea点击:

Qt Linker Error: "undefined reference to vtable"

c++qtlinker-errorsvtableqobject

提问by Thomas

This is my header:

这是我的标题:

#ifndef BARELYSOCKET_H
#define BARELYSOCKET_H

#include <QObject>
//! The First Draw of the BarelySocket!

class BarelySocket: public QObject
{
    Q_OBJECT

public:
    BarelySocket();
public slots:
    void sendMessage(Message aMessage);
signals:
    void reciveMessage(Message aMessage);

private:
    //   QVector<Message> reciveMessages;
};

#endif // BARELYSOCKET_H

This is my class:

这是我的课:

#include <QTGui>
#include <QObject>
#include "type.h"
#include "client.h"
#include "server.h"

#include "barelysocket.h"

BarelySocket::BarelySocket()
{
    //this->reciveMessages.clear();
    qDebug("BarelySocket::BarelySocket()");
}

void BarelySocket::sendMessage(Message aMessage)
{
}

void BarelySocket::reciveMessage(Message aMessage)
{
}

I get a Linker error:

我收到链接器错误:

undefined reference to 'vtable for BarelySocket'
  • This implies that I have a virtual method not implemented. But there are no virtual methods in my class.
  • I commented out the vector thinking that it was the cause, but the error did not go away.
  • The Messageis a complex struct, but even using intinstead did not fix things.
  • 这意味着我有一个未实现的虚拟方法。但是我的类中没有虚拟方法。
  • 我注释掉了向量,认为这是原因,但错误并没有消失。
  • Message是一个复杂的struct,但即使使用int代替也没有解决问题。

回答by Michael

Any time you add a new call to the Q_OBJECT macro, you need to run qmake again. The vtables issue you're referring to is directly related to that.

每当您向 Q_OBJECT 宏添加新调用时,都需要再次运行 qmake。您所指的 vtables 问题与此直接相关。

Just run qmake and you should be good to go assuming there are no other issues in your code.

只需运行 qmake ,假设您的代码中没有其他问题,您应该很高兴。

回答by Sebastian Redl

I've seen a lot of ways to solve the problem, but no explanation for why it happens, so here goes.

我已经看到了很多解决问题的方法,但没有解释为什么会发生,所以这里是。

When the compiler sees a class with virtual functions (directly declared or inherited), it must generate a vtable for that class. Since classes are generally defined in headers (and thus appear in multiple translation units), the question is where to place the vtable.

当编译器看到一个带有虚函数(直接声明或继承)的类时,它必须为该类生成一个虚表。由于类通常在标题中定义(因此出现在多个翻译单元中),问题是在哪里放置 vtable。

In general, the problem can be solved by generating the vtable in every TU where the class is defined, and then let the linker eliminate duplicates. Since class definitions are required to be the same on every occurrence by the ODR, this is safe. However, it also slows down compilation, bloats object files, and requires the linker to do more work.

一般来说,可以通过在定义类的每个TU中生成vtable,然后让链接器消除重复项来解决问题。由于 ODR 要求类定义在每次出现时都相同,因此这是安全的。但是,它也会减慢编译速度,使目标文件膨胀,并且需要链接器做更多的工作。

As an optimization, therefore, compilers will, when possible, choose a specific TU to put the vtable in. In the common C++ ABI, this TU is the one where the key functionof the class is implemented in, where the key function is the first virtual member function that is declared in the class, but not defined.

因此,作为一种优化,编译器会在可能的情况下选择一个特定的 TU 来放置 vtable。在常见的 C++ ABI 中,这个 TU是实现类的关键函数的地方,其中关键函数是在类中声明但未定义的第一个虚拟成员函数。

In the case of Qt classes, they usually start with the Q_OBJECT macro, and this macro contains the declaration

对于 Qt 类,它们通常以 Q_OBJECT 宏开头,该宏包含声明

virtual const QMetaObject *metaObject() const;

which, since it is the first virtual function in the macro, will generally be the first virtual function of the class and thus its key function. The compiler will therefore not emit the vtable in most TUs, only the one that implements metaObject. And this function's implementation is written automatically by mocwhen it processes the header. Thus, you need to have mocprocess your header to generate a new .cpp file, and then include the .cpp file in your compilation.

因为它是宏中的第一个虚函数,所以通常是类的第一个虚函数,因此是它的关键函数。因此,编译器不会在大多数 TU 中发出 vtable,只会发出实现metaObject. 这个函数的实现是moc在它处理头时自动编写的。因此,您需要moc处理头文件以生成新的 .cpp 文件,然后在编译中包含 .cpp 文件。

So when you have a new header that defines a QObject-derived class, you need to rerun qmakeso that it updates your makefiles to run mocon the new header and compile the resulting .cpp file.

因此,当您有一个定义 -QObject派生类的新头文件时,您需要重新运行,qmake以便它更新您的 makefile 以moc在新头文件上运行并编译生成的 .cpp 文件。

回答by David

I ran into this error after I created a little class inside a small "main.cpp" file that I had created to test something.

在我为测试某些内容而创建的小“main.cpp”文件中创建了一个小类后,我遇到了这个错误。

After futzing for an hour or so, I finally moved that class out of main.cpp and into a standalone hpp file, updated the .pro (project) file and the project then built perfectly fine. That may not have been the issue here but I figured it would be useful information anyway.

在 futzing 一个小时左右之后,我终于将那个类从 main.cpp 移到了一个独立的 hpp 文件中,更新了 .pro(项目)文件,然后项目构建得非常好。这可能不是这里的问题,但我认为无论如何这都是有用的信息。

回答by Ronny Brendel

From experience: oftentimes a qmake && make clean && make helps. I personally perceive that sometimes the change discovery / caching effects / whatever-I-don't-know xxxxx. I can't say why, but it's the first thing I do when I encounter this kind of error.

根据经验:通常 qmake && make clean && make 有帮助。我个人认为有时更改发现/缓存效果/我不知道的xxxxx。我说不出为什么,但这是我遇到这种错误时做的第一件事。

btw. there's a typo at > recive <

顺便提一句。> recive < 有一个拼写错误

You forgot to call the QObject constructor in your constructor (in the initializer list). (It doesn't resolve the error though)

您忘记在构造函数中调用 QObject 构造函数(在初始化列表中)。(虽然它并没有解决错误)

回答by lstipakov

For me, I noticed from build logs that moc wasn't called. Clean All didn't help. So I removed .pro.user, restarted IDE and it did the trick.

对我来说,我从构建日志中注意到没有调用 moc。Clean All 没有帮助。所以我删除了 .pro.user,重新启动了 IDE,它成功了。

回答by Patrice Bernassola

Signals must not have an implementation (This wil be generated by Qt). Remove the reciveMessageimplementation from your .cpp file. This may solve your problem.

信号不能有实现(这将由 Qt 生成)。reciveMessage从 .cpp 文件中删除实现。这可能会解决您的问题。

An other thing I've seen: Since the BarelySocketclass inherit from QObject it must have a virtual destructor to avoid problem during destruction. This must be done for all class that inherit from an other class.

我看到的另一件事:由于BarelySocket类继承自 QObject,它必须有一个虚拟析构函数以避免在销毁过程中出现问题。必须对从其他类继承的所有类执行此操作。

回答by Pete

When you derive a class from QOBject (and use the Q_OBJECT macro), don't forget to specifically define and create both the constructor and destructor classes. It's not enough to use the compiler default constructor/destructors. The advice on cleaning/running qmake (and clearing out your moc_ files) still applies. This fixed my similar problem.

当您从 QOBject 派生一个类(并使用 Q_OBJECT 宏)时,不要忘记专门定义和创建构造函数和析构函数类。使用编译器默认构造函数/析构函数是不够的。关于清理/运行 qmake(并清除您的 moc_ 文件)的建议仍然适用。这解决了我的类似问题。

回答by Sunny127

I struggled with this error hours. Solved it by putting the .cpp and .h file in a separate folder (!!) . Then added the folder in the .pro file : INCLUDEPATH += $${_PRO_FILE_PWD_}/../MyClasses/CMyClassWidget

我在这个错误小时内挣扎。通过将 .cpp 和 .h 文件放在一个单独的文件夹 (!!) 来解决它。然后在 .pro 文件中添加文件夹:INCLUDEPATH += $${_PRO_FILE_PWD_}/../MyClasses/CMyClassWidget

and then added the .cpp and .h file. Works at last.

然后添加了 .cpp 和 .h 文件。终于工作了。

回答by Preston

I found another reason why you might see this - since qmakeparses through your class files if you have modified them in a non-standard way you may get this error. In my case I had a custom dialog that inherited from QDialog, but I only wanted that to compile and run when building for Linux, not Windows or OSX. I just #ifdef __linux__the class out so it didn't compile, but in Linux even though __linux__was defined it was throwing off qmake.

我找到了您可能会看到这一点的另一个原因 - 因为qmake如果您以非标准方式修改了类文件,则会解析它们,您可能会收到此错误。就我而言,我有一个从 QDialog 继承的自定义对话框,但我只希望在为 Linux 而不是 Windows 或 OSX 构建时编译和运行它。我只是#ifdef __linux__把这个类放出来,所以它没有编译,但在 Linux 中,即使__linux__被定义,它也被扔掉了qmake