PDA

View Full Version : Problem with the Qt docs



Morea
21st February 2006, 12:20
Hi.
I try to compile the example of the QObject derived class "Counter" on
http://doc.trolltech.com/4.1/signalsandslots.html
but I only get this error:


g++ -c -pipe -O2 -march=athlon-xp -pipe -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I/usr/share/doc/qt-4.1.0-r2/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4 -I. -I. -I. -o q.o q.cpp
g++ -o snor q.o -L/usr/lib/qt4 -lQtGui -L/usr/lib/mysql -L/usr/lib -L/usr/lib/qt4 -laudio -lXt -lpng -lSM -lICE -lXi -lXrender -lXrandr -lXcursor -lfreetype -lfontconfig -lXext -lX11 -lQtCore -lz -lm -ldl -lpthread
q.o: In function `main':
q.cpp:(.text+0x4b): undefined reference to `vtable for Counter'
q.cpp:(.text+0x69): undefined reference to `vtable for Counter'
q.cpp:(.text+0xbb): undefined reference to `vtable for Counter'
q.cpp:(.text+0xcd): undefined reference to `vtable for Counter'
q.cpp:(.text+0xe8): undefined reference to `vtable for Counter'
q.o:q.cpp:(.text+0xf7): more undefined references to `vtable for Counter' follow
q.o: In function `Counter::setValue(int)':
q.cpp:(.text+0x16): undefined reference to `Counter::valueChanged(int)'
collect2: ld returned 1 exit status
make: *** [snor] Error 1

What's wrong?
Here is the code:


#include <QObject>

class Counter : public QObject
{
Q_OBJECT
public:
Counter() { m_value = 0; }
int value() const { return m_value; }
public slots:
void setValue(int value);
signals:
void valueChanged(int newValue);
private:
int m_value;
};


void Counter::setValue(int value)
{
if (value != m_value) {
m_value = value;
emit valueChanged(value);
}
}


int main()
{
Counter a, b;
QObject::connect(&a, SIGNAL(valueChanged(int)),
&b, SLOT(setValue(int)));
a.setValue(12); // a.value() == 12, b.value() == 12
b.setValue(48); // a.value() == 12, b.value() == 48
}

wysota
21st February 2006, 12:42
Separate the class header and implementation (put them into separate files). And call superclass constructor in the constructor of the derived class.

Morea
21st February 2006, 12:48
Why would a header/implementation separation solve the problem? Or is that just a magic MOC thing that I have to accept?

wysota
21st February 2006, 13:00
Why would a header/implementation separation solve the problem? Or is that just a magic MOC thing that I have to accept?

Yes. moc won't work properly without it. There is a workaround for this, but it's not worth the effort.

michel
21st February 2006, 13:04
Your thread subject is "Problem with the Qt docs." I actually found something in the docs the other day when trying to find an answer for somebody else that was like, "We cannot stress enough that the most common bug people find in their software is an error about missing vtables. This 99% of the time means you forgot to run the moc on your code."

I can't seem to find it now, but I found this instead:



Diagnostics

moc will warn you about a number of dangerous or illegal constructs in the Q_OBJECT class declarations.

If you get linkage errors in the final building phase of your program, saying that YourClass::className() is undefined or that YourClass lacks a vtable, something has been done wrong. Most often, you have forgotten to compile or #include the moc-generated C++ code, or (in the former case) include that object file in the link command. If you use qmake, try rerunning it to update your makefile. This should do the trick.



Why would a header/implementation separation solve the problem? Or is that just a magic MOC thing that I have to accept?

Because MOC doesn't look at your .cpp files for Q_OBJECT unless you tell it to. Under normal circumstances it only cares about the .h files. From the manual for MOC, however, is the following:


For Q_OBJECT class declarations in implementation (.cpp) files, we suggest a makefile rule like this:

foo.o: foo.moc

foo.moc: foo.cpp
moc -i $< -o $@

This guarantees that make will run the moc before it compiles foo.cpp. You can then put

#include "foo.moc"

at the end of foo.cpp, where all the classes declared in that file are fully known.

So it's not impossible, it's just not as easy as keeping your declarations separate from the implementation and doing "qmake -project ; qmake ; make." I think actually in many of the examples with the docs, there is a piece of code in main.cpp that says "#include main.moc" at the bottom. Is it in your Counter example or no? That is what this line means.

Cesar
21st February 2006, 13:05
Why would a header/implementation separation solve the problem? Or is that just a magic MOC thing that I have to accept?
Yes :) It is!

Morea
21st February 2006, 13:11
Thank you all for your answers.