开发者

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.


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.


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.


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.


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)


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.


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.


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.


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜