Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. A nasty problem with moc
Qt 6.11 is out! See what's new in the release blog

A nasty problem with moc

Scheduled Pinned Locked Moved Unsolved General and Desktop
11 Posts 3 Posters 793 Views 3 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • PerdrixP Perdrix

    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!!!!!

    jeremy_kJ Online
    jeremy_kJ Online
    jeremy_k
    wrote on last edited by
    #2

    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.

    Asking a question about code? http://eel.is/iso-c++/testcase/

    PerdrixP 1 Reply Last reply
    1
    • jeremy_kJ jeremy_k

      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.

      PerdrixP Offline
      PerdrixP Offline
      Perdrix
      wrote on last edited by
      #3

      @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.

      Christian EhrlicherC 1 Reply Last reply
      0
      • jeremy_kJ Online
        jeremy_kJ Online
        jeremy_k
        wrote on last edited by
        #4

        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.

        Asking a question about code? http://eel.is/iso-c++/testcase/

        PerdrixP 1 Reply Last reply
        2
        • jeremy_kJ jeremy_k

          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.

          PerdrixP Offline
          PerdrixP Offline
          Perdrix
          wrote on last edited by
          #5

          @jeremy_k Neither option there seems helpful

          1 Reply Last reply
          0
          • PerdrixP Perdrix

            @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.

            Christian EhrlicherC Offline
            Christian EhrlicherC Offline
            Christian Ehrlicher
            Lifetime Qt Champion
            wrote on last edited by
            #6

            @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.

            Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
            Visit the Qt Academy at https://academy.qt.io/catalog

            PerdrixP 1 Reply Last reply
            4
            • Christian EhrlicherC Christian Ehrlicher

              @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.

              PerdrixP Offline
              PerdrixP Offline
              Perdrix
              wrote on last edited by Perdrix
              #7

              @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 EhrlicherC 1 Reply Last reply
              0
              • PerdrixP Perdrix

                @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 EhrlicherC Offline
                Christian EhrlicherC Offline
                Christian Ehrlicher
                Lifetime Qt Champion
                wrote on last edited by
                #8

                @Perdrix I will not read or comment your code until you add proper formatting with the code tags...

                Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                Visit the Qt Academy at https://academy.qt.io/catalog

                PerdrixP 1 Reply Last reply
                0
                • Christian EhrlicherC Christian Ehrlicher

                  @Perdrix I will not read or comment your code until you add proper formatting with the code tags...

                  PerdrixP Offline
                  PerdrixP Offline
                  Perdrix
                  wrote on last edited by
                  #9

                  @Christian-Ehrlicher Updated

                  PerdrixP 1 Reply Last reply
                  0
                  • PerdrixP Perdrix

                    @Christian-Ehrlicher Updated

                    PerdrixP Offline
                    PerdrixP Offline
                    Perdrix
                    wrote on last edited by
                    #10

                    @Perdrix Replacing with dynamic_cast in original code also worked.

                    My this crow is tasty :)

                    1 Reply Last reply
                    0
                    • jeremy_kJ Online
                      jeremy_kJ Online
                      jeremy_k
                      wrote on last edited by
                      #11

                      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 { };
                      

                      Asking a question about code? http://eel.is/iso-c++/testcase/

                      1 Reply Last reply
                      0

                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved