Qt链接器错误:“vtable未定义引用”[重复]

时间:2022-03-14 18:45:41

This question already has an answer here:

这个问题已经有了答案:

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 Message is a complex struct, but even using int instead did not fix things.
  • 消息是一个复杂的结构体,但即使使用int也不能修复问题。

9 个解决方案

#1


117  

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就可以了,如果代码中没有其他问题的话,那么您就应该走了。

#2


26  

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。由于类通常在header中定义(因此出现在多个翻译单元中),所以问题是如何放置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 function of 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 moc when it processes the header. Thus, you need to have moc process your header to generate a new .cpp file, and then include the .cpp file in your compilation.

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

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

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

#3


12  

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.

经过大约一个小时的反复练习,我终于把那门课从主课上挪开了。cpp和一个独立的hpp文件,更新了.pro(项目)文件,然后项目构建得非常好。这可能不是问题所在,但我认为这是有用的信息。

#4


10  

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 help。我个人认为,有时候变更发现/缓存效果/无论如何我都不知道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构造函数了。(虽然不能解决错误)

#5


3  

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没有被调用。清洁所有没有帮助。所以我.pro删除。用户,重新启动IDE,它成功了。

#6


2  

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

信号必须没有实现(这个将由Qt生成)。从.cpp文件中删除reciveMessage实现。这也许能解决你的问题。

An other thing I've seen: Since the BarelySocket class 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,它必须有一个虚拟析构函数,以避免在销毁过程中出现问题。必须对从其他类继承的所有类执行此操作。

#7


2  

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_文件)的建议仍然适用。这解决了我的类似问题。

#8


1  

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/ cmyclassclasswidget

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

然后添加。cpp和。h文件。在最后的工作。

#9


0  

I found another reason why you might see this - since qmake parses 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。

#1


117  

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就可以了,如果代码中没有其他问题的话,那么您就应该走了。

#2


26  

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。由于类通常在header中定义(因此出现在多个翻译单元中),所以问题是如何放置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 function of 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 moc when it processes the header. Thus, you need to have moc process your header to generate a new .cpp file, and then include the .cpp file in your compilation.

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

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

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

#3


12  

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.

经过大约一个小时的反复练习,我终于把那门课从主课上挪开了。cpp和一个独立的hpp文件,更新了.pro(项目)文件,然后项目构建得非常好。这可能不是问题所在,但我认为这是有用的信息。

#4


10  

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 help。我个人认为,有时候变更发现/缓存效果/无论如何我都不知道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构造函数了。(虽然不能解决错误)

#5


3  

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没有被调用。清洁所有没有帮助。所以我.pro删除。用户,重新启动IDE,它成功了。

#6


2  

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

信号必须没有实现(这个将由Qt生成)。从.cpp文件中删除reciveMessage实现。这也许能解决你的问题。

An other thing I've seen: Since the BarelySocket class 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,它必须有一个虚拟析构函数,以避免在销毁过程中出现问题。必须对从其他类继承的所有类执行此操作。

#7


2  

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_文件)的建议仍然适用。这解决了我的类似问题。

#8


1  

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/ cmyclassclasswidget

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

然后添加。cpp和。h文件。在最后的工作。

#9


0  

I found another reason why you might see this - since qmake parses 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。