Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Define a QObject derived class inside an anonymous namespace?

Tags:

c++

qt

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

like image 445
pablo_worker Avatar asked Jan 05 '23 18:01

pablo_worker


1 Answers

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"
like image 138
Kuba hasn't forgotten Monica Avatar answered Jan 19 '23 00:01

Kuba hasn't forgotten Monica