I have a Qt application with multiple classes that use signals and slots and it compiles just fine. However, when I make a custom class inside the main CPP (main.cpp) file, I get a linker error.
Here is the code I use:
class Counter : public QObject
{
Q_OBJECT
public:
Counter() { m_value = 0; }
int value() const { return m_value; }
public slots:
void setValue(int value)
{
if(value!=m_value)
{
m_value = value;
qDebug() << "Value " << value;
emit valueChanged(value);
}
}
signals:
void valueChanged(int newValue);
private:
int m_value;
};
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
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
QTimer::singleShot(0, &app, SLOT(quit()));
return app.exec();
}
Here are the errors:
Error 4 error LNK2001: unresolved external symbol "public: virtual struct QMetaObject const * __thiscall Counter::metaObject(void)const " (?metaObject@Counter@@UBEPBUQMetaObject@@XZ)
Error 5 error LNK2001: unresolved external symbol "public: virtual void * __thiscall Counter::qt_metacast(char const *)" (?qt_metacast@Counter@@UAEPAXPBD@Z)
Error 6 error LNK2001: unresolved external symbol "public: virtual int __thiscall Counter::qt_metacall(enum QMetaObject::Call,int,void * *)" (?qt_metacall@Counter@@UAEHW4Call@QMetaObject@@HPAPAX@Z)
Error 7 error LNK2019: unresolved external symbol "protected: void __thiscall Counter::valueChanged(int)" (?valueChanged@Counter@@IAEXH@Z) referenced in function "public: void __thiscall Counter::setValue(int)" (?setValue@Counter@@QAEXH@Z)
This linker error does not occur when I place the counter in a separate header file. What’s the reason for this behavior?
I’m assuming you’re working with
qmake.The
mocis made to run on header files automatically by default, because that’s where classes are declared in general. Notice that this rule is defined in the makefile, you can manually runmocon a source file.You have to inform
qmakethat the file contains a class. To do this, put#include "filename.moc"after the declaration ofCounter. You can see more details here (QtCentre) or here (doc).If you’re working with another tool than
qmake, say CMake, you have to specify a rule to force the moc to parse the.cppfiles (the simplest is to process them all). For files that do not contain a Qt object class,mocwill generate an empty file.However, even if this class is made to be ‘private’, I advise you to declare it in a header (for example
counter_private.h). For example, Qt source is using this trick.