簡體   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