我正在使用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:未解析的外部符号&#34; public:virtual struct QMetaObject const * __cdecl`anonymous namespace&#39; :: CUtility :: metaObject(void)const&#34; (?metaObject @ CUtility @?A0x27a8253c @@ UEBAPEBUQMetaObject @@ XZ)
LNK2001:未解析的外部符号&#34; public:virtual void * __cdecl`anonymous namespace&#39; :: CUtility :: qt_metacast(char const *)&#34; (?qt_metacast @ CUtility @?A0x27a8253c @@ UEAAPEAXPEBD @ Z)sin resolver
LNK2001:未解析的外部符号&#34; public:virtual int __cdecl`anonymous namespace&#39; :: CUtility :: qt_metacall(enum QMetaObject :: Call,int,void * *)&#34; (?qt_metacall @ CUtility @?A0x27a8253c @@ UEAAHW4Call @ QMetaObject @@ HPEAPEAX @ Z)sin resolver
答案 0 :(得分:3)
它不适用于Q_OBJECT
宏,因为宏会向您的类添加成员,这些成员在由moc生成的C ++代码中定义(通常在moc_CMyClass.cpp
中使其与a不兼容文件范围)。
一种可能的解决方案是跳过Q_OBJECT
宏,它不是强制性的,您可能不需要它。缺点是您将失去关于您的类的内省信息,并且不能声明信号和插槽。
正如@KubaOber所建议的那样,另一个解决方案是将生成的cpp文件包含在您自己的副本文件的末尾。在这种情况下,qmake
将检测它并且不会编译moc
cpp文件本身。
答案 1 :(得分:3)
这与匿名命名空间完全没有关系。事实上,它们是不合理的。
回想一下,moc生成一些方法的实现,包括信号和一些静态数据。为此,类声明必须对moc输出可见。它在.cpp
文件的末尾可见。
因此,要在Q_OBJECT
文件中包含foo.cpp
类,您必须在该文件的末尾#include "foo.moc"
。然后重新运行qmake并再次构建项目。这就是全部。
在下面的完整示例中,Utility
类可以位于匿名命名空间中,但并非必须如此。匿名命名空间不是真的&#34;真的&#34;命名空间:它具有特殊含义,将包含的标识符的范围限制为转换单元。它与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"