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