繁体   English   中英

在匿名命名空间内定义 QObject 派生类?

[英]Define a QObject derived class inside an anonymous namespace?

我正在使用 Qt 5.7 (C++)。

在一个类的 cpp 文件中,我使用匿名命名空间来创建一个仅在该文件中使用的类(某些实用程序)。

但是,如果实用程序类派生自 Qt 类,则会出现链接错误。 我认为问题出在 Q_OBJECT 宏上,如果我不添加它,我就不会收到错误消息。 但是在任何 Qt 派生类中都必须/推荐使用 Q_OBJECT 宏。

我怎样才能避免这个问题? 有没有其他方法可以让实用程序类具有文件范围?

显示错误的简单示例:类 CMyClass 使用派生自 QWidget 的实用程序类(名为 CUtility)。

谢谢你。

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();
}

错误是:

LNK2001:未解析的外部符号“public: virtual struct QMetaObject const * __cdecl `匿名命名空间'::CUtility::metaObject(void)const” (?metaObject@CUtility@?A0x27a8253c@@UEBAPEBUQMetaObject@@XZ)

LNK2001:未解析的外部符号“public: virtual void * __cdecl `匿名命名空间'::CUtility::qt_metacast(char const *)” (?qt_metacast@CUtility@?A0x27a8253c@@UEAAPEAXPEBD@Z) 罪解析器

LNK2001:未解析的外部符号“public: virtual int __cdecl `匿名命名空间'::CUtility::qt_metacall(enum QMetaObject::Call,int,void * *)” (?qt_metacall@CUtility@?A0x27a8253c@@UEAAHW4Call@QMetaObject@@ HPEAPEAX@Z) sin 解析器

这与匿名命名空间完全无关。 事实上,它们是不合逻辑的。

回想一下, moc 生成了一些方法的实现,包括信号和一些静态数据。 为此,类声明必须对 moc 输出可见。 它在.cpp文件的末尾可见。

因此,要在foo.cpp文件中包含Q_OBJECT类,您必须在该文件的末尾#include "foo.moc" 如果使用 cmake,则只需重新构建,或者,对于 qmake,首先重新运行 qmake,然后构建项目。 就这样。

在下面的完整示例中, Utility类可以位于匿名命名空间中,但并非必须如此。 匿名命名空间并不是“真正的”命名空间:它具有特殊的含义,将包含的标识符的范围限制为翻译单元。 它就像static ,除了它也可以应用于类型,而不仅仅是函数和变量。

// 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"

它不适用于Q_OBJECT宏,因为该宏将成员添加到您的类中,这些成员在 moc 生成的 C++ 代码中定义(通常在moc_CMyClass.cpp ,使其与文件范围不兼容)。

一种可能的解决方案是跳过Q_OBJECT宏,它不是强制性的,您可能不需要它。 缺点是您将丢失有关您的类的内省信息,并且无法声明信号和槽。

另一种解决方案是,正如@KubaOber 所建议的那样,将生成的 cpp 文件包含在您自己的副本文件的末尾。 在这种情况下, qmake将检测到它并且不会自行编译 moc cpp 文件。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM