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

A nasty problem with moc

Scheduled Pinned Locked Moved Unsolved General and Desktop
11 Posts 3 Posters 726 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 Offline
    PerdrixP Offline
    Perdrix
    wrote on last edited by
    #1

    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 1 Reply Last reply
    0
    • 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 Offline
      jeremy_kJ Offline
      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 Offline
          jeremy_kJ Offline
          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 Online
              Christian EhrlicherC Online
              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 Online
                  Christian EhrlicherC Online
                  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 Offline
                        jeremy_kJ Offline
                        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