73

I'm using Qt Creator 2.0.1 with Qt 4.7.0 (32 bit) on Windows 7 Ultimate 32 bit.

Consider the following code, which is a minimum to produce the error:

class T : public QObject, public QGraphicsItem
{
    Q_OBJECT

public:
    T() {}

    QRectF      boundingRect() const {return QRectF();}
    void        paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
                      QWidget *widget) {}
};

int main()
{
    T t;
    return 0;
}

The above code fragment causes the following linker errors:

In function `T':

undefined reference to `vtable for T'

undefined reference to `vtable for T'

In function `~T':

undefined reference to `vtable for T'

undefined reference to `vtable for T'

If I comment out the line that contains Q_OBJECT, it compiles fine. I need signal and slots with QGraphicsItem so I need Q_OBJECT.

What is wrong with the code? Thanks.

Donotalo
  • 12,748
  • 25
  • 83
  • 121

5 Answers5

141

It is because the unit generated by MOC isn't included in the linking process. Or maybe it isn't generated at all. The first thing I'd do is to put the class declaration in a separate header file, perhaps the build system isn't scanning implementation files.

Another possibility is that the class in question once didn't belong to Qt meta object system (that is, it had no Q_OBJECT or maybe didn't inherit from QObject at all), so qmake needs to be run again in order to create the necessary rules for MOC. The easiest way to force qmake to be run is to make some insignificant changes to the project file to update its timestamp, like adding and then removing some white space. Or, if you're using Qt Creator, then just select “Run qmake” from the project context menu.

Sergei Tachenov
  • 24,345
  • 8
  • 57
  • 73
  • in my actual implementation, the class is separated in header and implementation file. the error exists there too. – Donotalo Jan 23 '11 at 14:45
  • @Donotalo, is the MOC run during compilation? Did you try clean and rebuild? – Sergei Tachenov Jan 23 '11 at 15:09
  • @Sergey Tachenov: Your suggestion that the unit is perhaps not generated by `moc` at all is the issue here since the class declaration is not in a header. – Troubadour Jan 23 '11 at 15:47
  • @Troubadour, the OP says in the comment above that in his real code the class declaration is in the header, and he still gets the error. So it's probably a Makefile update issue. – Sergei Tachenov Jan 23 '11 at 16:13
  • 4
    thanks for the ideas. i cleaned and rebuilt the project but it didn't work. then i edited the *.pro file and recompiled. it fixed the problem! – Donotalo Jan 24 '11 at 14:50
  • 4
    Spot on answer - covered my case where the object did not originally belong to the Qt meta object system. Simply editing the file did not work for me though. I had to remove my .user file and touch the *.pro file as @Donotalo suggested. After running qMake once more, life was good again. – Alex Hendren Nov 06 '13 at 07:32
  • I added a space in any line of my .pro file and rebuild the project...it saved my life! – Talysson de Castro Nov 24 '16 at 17:34
  • Spot on answer from post. In my case, implementation wasnt in header file – Dean P Aug 18 '19 at 09:57
27

If you want to define a QObject subclass in a source file then you need to add the line

#include "file.moc"

at some point after your class definition where the name of the source file was file.cpp. You will need to re-run qmake of course so that the appropriate rule to run moc gets added to the Makefile.

Only when in a header file does the presence of Q_OBJECT in a class definition cause moc to be invoked. If it's a source file you need this extra line to force moc to be used.

I'm sure a similar question has been asked before but I couldn't find it.

Troubadour
  • 13,334
  • 2
  • 38
  • 57
  • Excellent, ive been looking for a way to do this for a couple of days now, was not aware of this, they don't tell you stuff like this in the QObject documentation. – osirisgothra Dec 15 '13 at 02:14
8

Put your Q_OBJECT classes in separate files. That is one .h and one .cpp for each class. Qt's meta-object macros are kind of picky in this regard.

Also, you can use QGraphicsObject for your purpose. Saves you some time there.

Edit: I see you are using Creator. Use its New C++ Class function in New File or Project to create the file in the "right way" :)

Stephen Chu
  • 12,724
  • 1
  • 35
  • 46
6

Here is working code added with all fixes provided in other questions (Tried clean compiling and these fixes help):

#include <QGraphicsItem>

class T : public QObject, public QGraphicsItem
{
    Q_OBJECT
    Q_INTERFACES(QGraphicsItem) //Required.

public:
    T() {}
    QRectF      boundingRect() const {return QRectF();}
    void        paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
                      QWidget *widget) {}
};

int main(int argc, char *argv[])
{
    T *t = new T;
    return 0;
}

#include "main.moc" // Required.

So actual credit to Troubadour and serge_gubenko

Tuukka Lindroos
  • 1,270
  • 10
  • 14
4

there are couple of thing to look at:

  1. Add QT += gui in your pro file
  2. Make sure you define your QObject-derived classes in your header files only (edit: as Troubadour noted, this is not required)
  3. Add Q_INTERFACES(QGraphicsItem) to the declaration of your T class

below is an example:

t.h:

class T : public QObject, public QGraphicsItem
{
    Q_OBJECT
    Q_INTERFACES(QGraphicsItem)

public:
    T();
    QRectF boundingRect() const;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
};

t.cpp:

T::T() {}

QRectF T::boundingRect() const
{
    return QRectF();
}

void T::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    Q_UNUSED(painter);
    Q_UNUSED(option);
    Q_UNUSED(widget);
}

I've tried compiling the code above and didn't have problems with it.

hope this helps, regards

serge_gubenko
  • 20,186
  • 2
  • 61
  • 64