ChatGPT解决这个技术问题 Extra ChatGPT

Qt Linker Error: "undefined reference to vtable" [duplicate]

This question already has answers here: Undefined reference to vtable. Trying to compile a Qt project (21 answers) Closed 5 years ago.

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.

Have you tried a clean build starting from running qmake? This can happen if moc doesn't process the header for your class for some reason.
I am working with QT Creator. I copied all the cpp Files into an new clean Projekt. I deleted the Slot Implementation that i faulti coded. Than the Problems where gone. Thank you for your help!

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

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


Within QT Creator use run qmake from the Build menu.
Thanks! From the command line, just using make normally also updates some qmake-related stuff, but apparently not enough. Explicitly running qmake is, indeed, required.
Running qmake not enough for me, I had to delete my build folder then recompile.
it's work, I just re-ran qmake
Not working for me. I tried all of this and nothing worked. I can build successfully when I delete Q_OBJECT macro and I think this is not a proper way!
S
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.

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

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.

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.

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


Awesome write-up. I'm using CMake instead of qmake, and I see this error pretty frequently; it's very frustrating to understand the basic C++ vtable information and still not be able to figure out what is going wrong. Thank you!
@Kyle Strand Shouldn't set(CMAKE_AUTOMOC ON) be sufficient? I have a Qt library and I have to run qmake every time to avoid the vtable error. Does this mean cmake is not running the moc as it should?
@JamesHirschorn You'd think that should be sufficient, yes. And indeed it appears that moc is re-run for every build without regard for whether the input files have actually changed. I'm not really sure what the fundamental CMake problem is.
I also have this problem with CMake, and yes I see the automoc running, but no files are generated. How do I get the automoc to scan the header file?
@xcski Good idea, added some definitions.
D
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.

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.


I did exactly the same mistake today! Also lost about an hour or so...
Any idea why this happens? Happened to me also today.
R
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.

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)


This is especially useful when the file has existed but didn't have any Q_OBJECT references in it when qmake was run. qmake then doesn't believe it needs to run moc and you end up with vtable errors. The make clean isn't always necessary, but is when certain structural changes are made.
Also make sure that barelysocket.h is in HEADERS section in your pro file.
l
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.


that's exactly what happened to me too. This QtCreator bug was triggered when I added a Class that is not a QObject parent, but later fixed it manually. I did grep Class Project.user and it was missing the file. So I just deleted the .user file, rebuilt everything and the error was gone
P
Patrice Bernassola

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.


Removing receiveMessage implementation is necessary, but it would rather cause "multiply defined symbol" error. If base class (QObject in this case) has virtual destructor, then destructors in all derived classes are automatically virtual. So that's not an issue here.
P
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.


S
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

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


P
Preston

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.