[英]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.