A nasty problem with moc
-
I have a class that's derived from a base class and also from QMainWindow.
The base class has:
class QString; class DSSBase { public: // severity 2 is QMessageBox::Warning virtual void reportError(const QString& message, int severity = 2) = 0; inline static DSSBase* instance() { return theInstance; } inline static void setInstance(DSSBase* instance) { ZASSERT(nullptr == theInstance); theInstance = instance; } private: static inline DSSBase* theInstance{ nullptr }; };and the derived class has:
public: inline static DeepSkyStacker* instance() { return reinterpret_cast<DeepSkyStacker *>(DSSBase::instance()); }So I have to code:
class DeepSkyStacker : public DSSBase, public QMainWindow {But if I do that, moc creates a moc_DeepSkyStacker file that results in the following errors:
1>C:\Users\amonra\Documents\GitHub\DSS\DeepSkyStacker\GeneratedFiles\moc_DeepSkyStacker.cpp(90,43): error C2039: 'staticMetaObject': is not a member of 'DSSBase' 1>C:\Users\amonra\Documents\GitHub\DSS\dssbase.h(44,7): message : see declaration of 'DSSBase' 1>C:\Users\amonra\Documents\GitHub\DSS\DeepSkyStacker\GeneratedFiles\moc_DeepSkyStacker.cpp(134,21): error C2039: 'qt_metacast': is not a member of 'DSSBase' 1>C:\Users\amonra\Documents\GitHub\DSS\dssbase.h(44,7): message : see declaration of 'DSSBase' 1>C:\Users\amonra\Documents\GitHub\DSS\DeepSkyStacker\GeneratedFiles\moc_DeepSkyStacker.cpp(139,20): error C2039: 'qt_metacall': is not a member of 'DSSBase' 1>C:\Users\amonra\Documents\GitHub\DSS\dssbase.h(44,7): message : see declaration of 'DSSBase'Arrggghhhh!!!!!
-
I have a class that's derived from a base class and also from QMainWindow.
The base class has:
class QString; class DSSBase { public: // severity 2 is QMessageBox::Warning virtual void reportError(const QString& message, int severity = 2) = 0; inline static DSSBase* instance() { return theInstance; } inline static void setInstance(DSSBase* instance) { ZASSERT(nullptr == theInstance); theInstance = instance; } private: static inline DSSBase* theInstance{ nullptr }; };and the derived class has:
public: inline static DeepSkyStacker* instance() { return reinterpret_cast<DeepSkyStacker *>(DSSBase::instance()); }So I have to code:
class DeepSkyStacker : public DSSBase, public QMainWindow {But if I do that, moc creates a moc_DeepSkyStacker file that results in the following errors:
1>C:\Users\amonra\Documents\GitHub\DSS\DeepSkyStacker\GeneratedFiles\moc_DeepSkyStacker.cpp(90,43): error C2039: 'staticMetaObject': is not a member of 'DSSBase' 1>C:\Users\amonra\Documents\GitHub\DSS\dssbase.h(44,7): message : see declaration of 'DSSBase' 1>C:\Users\amonra\Documents\GitHub\DSS\DeepSkyStacker\GeneratedFiles\moc_DeepSkyStacker.cpp(134,21): error C2039: 'qt_metacast': is not a member of 'DSSBase' 1>C:\Users\amonra\Documents\GitHub\DSS\dssbase.h(44,7): message : see declaration of 'DSSBase' 1>C:\Users\amonra\Documents\GitHub\DSS\DeepSkyStacker\GeneratedFiles\moc_DeepSkyStacker.cpp(139,20): error C2039: 'qt_metacall': is not a member of 'DSSBase' 1>C:\Users\amonra\Documents\GitHub\DSS\dssbase.h(44,7): message : see declaration of 'DSSBase'Arrggghhhh!!!!!
https://doc.qt.io/qt-6/moc.html#multiple-inheritance-requires-qobject-to-be-first:
If you are using multiple inheritance, moc assumes that the first inherited class is a subclass of QObject.
-
https://doc.qt.io/qt-6/moc.html#multiple-inheritance-requires-qobject-to-be-first:
If you are using multiple inheritance, moc assumes that the first inherited class is a subclass of QObject.
@jeremy_k Yes, that was immediately obvious.
Is there a clever way to work round this problem? As things stand right now I need DSSBase to be first, otherwise the pointer to base class and to derived class stuff doesn't work.
OTOH moc wants (in this case) QMainWindow first.
-
My point wasn't that it wasn't obvious, but that this has been a documented requirement for decades. You can forgo moc entirely, either by writing the code manually, or through a 3rd party implementation such as Verdigris.
-
@jeremy_k Yes, that was immediately obvious.
Is there a clever way to work round this problem? As things stand right now I need DSSBase to be first, otherwise the pointer to base class and to derived class stuff doesn't work.
OTOH moc wants (in this case) QMainWindow first.
@Perdrix said in A nasty problem with moc:
otherwise the pointer to base class and to derived class stuff doesn't work.
Then fix your code - dynamic_cast<> is what you're looking for.
-
@Perdrix said in A nasty problem with moc:
otherwise the pointer to base class and to derived class stuff doesn't work.
Then fix your code - dynamic_cast<> is what you're looking for.
@Christian-Ehrlicher This seems to work:
class DSSBase { public: // severity 2 is QMessageBox::Warning virtual void reportError(const QString& message, int severity = 2) = 0; inline static DSSBase* instance() { return theInstance; } inline static void setInstance(DSSBase* instance) { ZASSERT(nullptr == theInstance); theInstance = instance; } private: static inline DSSBase* theInstance{ nullptr }; }; class DeepSkyStacker public QMainWindow, public DSSBase { private: static inline DeepSkyStacker* theInstance{ nullptr }; public: inline static DeepSkyStacker* instance() { return theInstance; } inline static void setInstance(DeepSkyStacker* instance) { ZASSERT(nullptr == theInstance); theInstance = instance; DSSBase::setInstance(static_cast<DSSBase*>(instance)); }I'm prepared to revert to the original with the reinterpret_cast replaced with dynamic_cast as suggested. But that's a task for tomorrow!
-
@Christian-Ehrlicher This seems to work:
class DSSBase { public: // severity 2 is QMessageBox::Warning virtual void reportError(const QString& message, int severity = 2) = 0; inline static DSSBase* instance() { return theInstance; } inline static void setInstance(DSSBase* instance) { ZASSERT(nullptr == theInstance); theInstance = instance; } private: static inline DSSBase* theInstance{ nullptr }; }; class DeepSkyStacker public QMainWindow, public DSSBase { private: static inline DeepSkyStacker* theInstance{ nullptr }; public: inline static DeepSkyStacker* instance() { return theInstance; } inline static void setInstance(DeepSkyStacker* instance) { ZASSERT(nullptr == theInstance); theInstance = instance; DSSBase::setInstance(static_cast<DSSBase*>(instance)); }I'm prepared to revert to the original with the reinterpret_cast replaced with dynamic_cast as suggested. But that's a task for tomorrow!
@Perdrix I will not read or comment your code until you add proper formatting with the code tags...
-
@Perdrix I will not read or comment your code until you add proper formatting with the code tags...
@Christian-Ehrlicher Updated
-
@Christian-Ehrlicher Updated
-
An intermediate class can also work, so moc isn't asked to deal with not having the QObject base first.
class Intermediate : public QObject { Q_OBJECT signals: void mySignal(); }; class OtherClass {}; class derived : public OtherClass, public Intermediate { };