I am working with Qt 5.7 (C++).
Inside the cpp file of one class I am using an anonymous namespace to create a class (some utility) that I will use only in that file.
However, I got Linking errors if the utility-class is derived from a Qt class. I think that the problem is at the Q_OBJECT macro, if I don't add it I don't get the errors. But in any Qt derived class is imperative/recommended to have the Q_OBJECT macro.
How can I avoid this isue? Is there any other approach to have a utility-class with file-scope?
Simple example to show errors: the class CMyClass uses a utility class (named CUtility) that derives from QWidget.
Thank you.
CMyClass.h
class CMyClass
{
public:
CMyClass();
void someMethod();
};
CMyClass.cpp
#include <QtWidgets>
#include "CMyClass.h"
namespace
{
class CUtility : public QWidget
{
Q_OBJECT
public:
CUtility(QWidget *p_parent = 0) : QWidget(p_parent){qDebug() << "CUtility constructor";}
void utilityMethod() {qDebug() << "This is CUtility::utilityMethod()";}
};
}
CMyClass::CMyClass()
{
qDebug() << "CMyClass constructor.";
}
void CMyClass::someMethod()
{
qDebug() << "This is CMyClass::someMethod().";
CUtility p_myUtil;
p_myUtil.utilityMethod();
}
The errors are:
LNK2001: unresolved external symbol "public: virtual struct QMetaObject const * __cdecl `anonymous namespace'::CUtility::metaObject(void)const " (?metaObject@CUtility@?A0x27a8253c@@UEBAPEBUQMetaObject@@XZ)
LNK2001: unresolved external symbol "public: virtual void * __cdecl `anonymous namespace'::CUtility::qt_metacast(char const *)" (?qt_metacast@CUtility@?A0x27a8253c@@UEAAPEAXPEBD@Z) sin resolver
LNK2001: unresolved external symbol "public: virtual int __cdecl `anonymous namespace'::CUtility::qt_metacall(enum QMetaObject::Call,int,void * *)" (?qt_metacall@CUtility@?A0x27a8253c@@UEAAHW4Call@QMetaObject@@HPEAPEAX@Z) sin resolver
This has nothing to do with anonymous namespaces at all. They are a non sequitur, in fact.
Recall that moc generates the implementations of a few methods, including signals, and some static data. For this to work, the class declaration must be visible to moc output. It is visible at the end of the .cpp
file.
Thus, to have a Q_OBJECT
class inside a foo.cpp
file, you must #include "foo.moc"
at the end of that file. Then just re-build if using cmake, or, for qmake, re-run qmake first and then build the project. That's all.
In the complete example below, the Utility
class can be in the anonymous namespace, but doesn't have to be. The anonymous namespace isn't "really" a namespace: it has a special meaning that limits the scope of the contained identifiers to the translation unit. It's like static
, except it can be also applied to types, not only functions and variables.
// main.cpp
#include <QObject>
namespace {
class Utility : public QObject {
Q_OBJECT
public:
Utility(QObject *parent = {});
};
}
Utility::Utility(QObject *parent) : QObject(parent) {}
int main() {
Utility utility;
}
#include "main.moc"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With