Qt 链接器错误:“未定义对 vtable 的引用”
这是我的标题:
#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
这是我的课程:
#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)
{
}
我收到链接器错误:
undefined reference to 'vtable for BarelySocket'
- 这意味着我有一个未实现的虚拟方法。但有 我的类中没有虚拟方法。
- 我注释掉了向量,认为这是原因,但是 错误并没有消失。
Message
是一个复杂的struct
,但即使使用int
也可以 不解决问题。
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 complexstruct
, but even usingint
instead did
not fix things.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
任何时候添加对 Q_OBJECT 宏的新调用时,都需要再次运行 qmake。您提到的 vtables 问题与此直接相关。
只需运行 qmake,假设您的代码中没有其他问题,您应该就可以开始了。
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.
Just run qmake and you should be good to go assuming there are no other issues in your code.
我已经看到了很多解决该问题的方法,但没有解释为什么会发生这种情况,所以这里是。
当编译器看到一个带有虚函数(直接声明或继承)的类时,它必须为该类生成一个虚函数表。由于类通常在标头中定义(因此出现在多个翻译单元中),因此问题是在哪里放置 vtable。
一般来说,可以通过在定义类的每个TU*中生成vtable,然后让链接器消除重复来解决该问题。由于 ODR** 要求类定义在每次出现时都相同,因此这是安全的。然而,它也会减慢编译速度,使目标文件膨胀,并且需要链接器做更多的工作。
因此,作为一种优化,编译器会在可能的情况下选择一个特定的 TU 来放入 vtable。在常见的 C++ ABI*** 中,该 TU 是类的关键函数所在的地方是在其中实现的,其中关键函数是在类中声明但未定义的第一个虚拟成员函数。
对于 Qt 类,它们通常以 Q_OBJECT 宏开头,并且该宏包含声明
,由于它是宏中的第一个虚函数,因此通常是该类的第一个虚函数,因此也是其关键函数。因此,编译器不会在大多数 TU 中生成 vtable,而只会生成实现
metaObject
的 vtable。这个函数的实现是由moc
在处理 header 时自动编写的。因此,您需要让moc
处理您的标头以生成新的 .cpp 文件,然后将该 .cpp 文件包含在您的编译中。因此,当您有一个定义
QObject
派生类的新标头时,您需要重新运行qmake
以便它更新您的 makefile 来运行moc
在新标头上并编译生成的 .cpp 文件。* TU:翻译单位。它是 C 和 C++ 中的一个术语,指的是单个源文件以及从中传递包含的所有头文件。基本上,编译器在处理单个源文件时看到的东西。
** ODR:一种定义规则。 C++ 标准中的一组规则,定义在不同的翻译单元中多次定义事物(函数、类等)时会发生什么情况。
*** ABI:应用程序二进制接口。编译时组织代码的方式的描述,对于将目标文件链接在一起是必需的。 Common C++ ABI 是 Linux 编译器通常遵循的规范,以便它们可以互操作。
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.
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.
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.
In the case of Qt classes, they usually start with the Q_OBJECT macro, and this macro contains the declaration
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 bymoc
when it processes the header. Thus, you need to havemoc
process your header to generate a new .cpp file, and then include the .cpp file in your compilation.So when you have a new header that defines a
QObject
-derived class, you need to rerunqmake
so that it updates your makefiles to runmoc
on the new header and compile the resulting .cpp file.* TU: Translation Unit. A term of art in C and C++, it refers to a single source file plus all the header files transitively included from it. Basically, the stuff the compiler sees when it works on a single source file.
** ODR: One Definition Rule. A set of rules in the C++ standard that define what happens when things (functions, classes, etc.) are defined multiple times in different translation units.
*** ABI: Application Binary Interface. A description of the way the code is organized when compiled, necessary for object files to be linked together. The Common C++ ABI is a specification that compilers for Linux generally follow so that they can interoperate.
在我为测试某些内容而创建的小“main.cpp”文件中创建了一个小类后,我遇到了此错误。
经过一个小时左右的摸索后,我终于将该类从 main.cpp 中移出并放入一个独立的 hpp 文件中,更新了 .pro (项目)文件,然后项目构建得非常好。这可能不是这里的问题,但我认为无论如何这都是有用的信息。
I ran into this error after I created a little class inside a small "main.cpp" file that I had created to test something.
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.
根据经验:通常是 qmake &&使清洁&&做出帮助。
我个人认为有时会改变发现/缓存效果/无论什么-我-不知道xxxxx。我不能说为什么,但这是我遇到这种错误时所做的第一件事。
顺便提一句。有一个拼写错误 >接收<
您忘记在构造函数中调用 QObject 构造函数(在初始值设定项列表中)。 (但它并不能解决错误)
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.
btw. there's a typo at > recive <
You forgot to call the QObject constructor in your constructor (in the initializer list). (It doesn't resolve the error though)
对我来说,我从构建日志中注意到 moc 没有被调用。全部清理没有帮助。所以我删除了 .pro.user,重新启动 IDE,它就成功了。
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.
信号不能有实现(这将由 Qt 生成)。从 .cpp 文件中删除
reciveMessage
实现。这可能会解决您的问题。我看到的另一件事是:由于
BarelySocket
类继承自 QObject,它必须有一个虚拟析构函数以避免析构过程中出现问题。必须对从其他类继承的所有类执行此操作。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.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.当您从 QOBject 派生类(并使用 Q_OBJECT 宏)时,不要忘记专门定义和创建构造函数和析构函数类。仅使用编译器默认构造函数/析构函数是不够的。关于清理/运行 qmake (并清除 moc_ 文件)的建议仍然适用。
这解决了我的类似问题。
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.
我在这个错误中挣扎了几个小时。通过将 .cpp 和 .h 文件放在单独的文件夹中解决了这个问题(!!)。
然后在 .pro 文件中添加该文件夹:
INCLUDEPATH += $${_PRO_FILE_PWD_}/../MyClasses/CMyClassWidget
,然后添加 .cpp 和 .h 文件。
终于可以工作了。
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
and then added the .cpp and .h file.
Works at last.
我发现了您可能会看到此错误的另一个原因 - 因为
qmake
会解析您的类文件,如果您以非标准方式修改了它们,则可能会收到此错误。就我而言,我有一个继承自 QDialog 的自定义对话框,但我只希望在为 Linux 而不是 Windows 或 OSX 构建时编译和运行它。我只是将#ifdef __linux__
类输出,因此它无法编译,但在 Linux 中,即使定义了__linux__
,它也会抛出qmake
。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 offqmake
.