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. Subclass of subclass of qobject

Subclass of subclass of qobject

Scheduled Pinned Locked Moved Solved General and Desktop
inheritancesubclassingqobject
10 Posts 4 Posters 9.3k Views
  • 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.
  • A Offline
    A Offline
    Alart
    wrote on 5 Feb 2016, 14:47 last edited by Alart 2 May 2016, 14:50
    #1

    Hi,
    I want to inherite QObject class in another class. But in this new class I want to add some Q_PROPERTY-ies too and register both as type to qml.
    Like that:
    baseclass.h

    #ifndef BASECLASS_H
    #define BASECLASS_H
    
    #include <QObject>
    
    class baseclass : public QObject
    {
    	protected:
    		Q_OBJECT
    		Q_PROPERTY(QString baseProperty READ baseProperty WRITE setBaseProperty NOTIFY basePropertyChanged)
    		QString m_baseProperty;
    
    	public:
    		explicit baseclass(QObject *parent = 0) :
    			QObject(parent)
    			{}
    		explicit baseclass(QString baseProperty, QObject *parent = 0) :
    			QObject(parent), m_baseProperty(baseProperty)
    			{}
    
    		~baseclass() {}
    
    		QString baseProperty() const
    		{
    			return m_baseProperty;
    		}
    
    	signals:
    		void basePropertyChanged(QString baseProperty);
    
    	public slots:
    		void setBaseProperty(QString baseProperty)
    		{
    			if (m_baseProperty == baseProperty)
    				return;
    
    			m_baseProperty = baseProperty;
    			emit basePropertyChanged(baseProperty);
    		}
    };
    
    #endif // BASECLASS_H
    
    

    inheritingclass.h

    #ifndef INHERITINGCLASS_H
    #define INHERITINGCLASS_H
    
    #include "baseclass.h"
    
    class inheritingclass : public baseclass
    {
    		Q_PROPERTY(QString newProperty READ newProperty WRITE setNewProperty NOTIFY newPropertyChanged)
    		QString m_newProperty;
    
    	public:
    		explicit inheritingclass(QObject *parent = 0) :
    			baseclass(parent)
    			{}
    		explicit inheritingclass(QString baseProperty, QString newProperty, QObject *parent = 0) :
    			baseclass(baseProperty, parent), m_newProperty(newProperty)
    			{}
    
    		~inheritingclass() {}
    
    		QString newProperty() const
    		{
    			return m_newProperty;
    		}
    
    	signals:
    		void newPropertyChanged(QString newProperty);
    
    	public slots:
    		void setNewProperty(QString newProperty)
    		{
    			if (m_newProperty == newProperty)
    				return;
    
    			m_newProperty = newProperty;
    			emit basePropertyChanged(newProperty);
    		}
    };
    
    #endif // INHERITINGCLASS_H
    

    main.cpp:

    #include <QApplication>
    #include <QQmlApplicationEngine>
    #include <QtQml>
    
    #include "baseclass.h"
    #include "inheritingclass.h"
    
    int main(int argc, char *argv[])
    {
    	QApplication app(argc, argv);
    
    	qmlRegisterType<baseclass>("example.inheritance",1,0,"baseClass");
    	qmlRegisterType<inheritingclass>("example.inheritance",1,0,"inheritingClass");
    
    	baseclass BaseClass("baseProperty of base class");
    	inheritingclass InheritingClass ("baseProperty of inheriting class", "new Property of inheriting clas");
    
    	QQmlApplicationEngine engine;
    
    	engine.rootContext()->setContextProperty("BaseClass", &BaseClass);
    	engine.rootContext()->setContextProperty("InheritingClass", &InheritingClass);
    
    	engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    
    	return app.exec();
    }
    
    

    main.qml:

    import QtQuick 2.5
    import QtQuick.Controls 1.4
    import QtQuick.Dialogs 1.2
    
    ApplicationWindow {
        visible: true
        width: 640
        height: 480
        title: qsTr("Hello World")
    
        menuBar: MenuBar {
            Menu {
                title: qsTr("File")
                MenuItem {
                    text: qsTr("Exit")
                    onTriggered: Qt.quit();
                }
            }
        }
    
        MainForm {
            anchors.fill: parent
            baseProperty.text:BaseClass.baseProperty
            inherBaseProp.text: InheritingClass.baseProperty
            newProperty.text: InheritingClass.newProperty
        }
    }
    
    

    MainForm.ui.qml

    import QtQuick 2.5
    import QtQuick.Controls 1.4
    import QtQuick.Layouts 1.2
    
    Item {
        id: item1
        width: 640
        height: 480
        property alias newProperty: newProperty
        property alias inherBaseProp: inherBaseProp
        property alias baseProperty: baseProperty
    
        ColumnLayout {
            id: columnLayout1
            anchors.fill: parent
    
            Text {
                id: baseProperty
                text: qsTr("this.id")
                Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
                font.pixelSize: 12
            }
    
            Text {
                id: inherBaseProp
                text: this.id
                Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
                font.pixelSize: 12
            }
    
            Text {
                id: newProperty
                text: this.id
                Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
                font.pixelSize: 12
            }
        }
    
    }
    
    

    But there inherining class isn't registered as a new type, and newProperty of inheriting class isn't displayed. My question is:

    How to register class that inherits from another custom qobject class as a type?

    1 Reply Last reply
    0
    • ? Offline
      ? Offline
      A Former User
      wrote on 5 Feb 2016, 15:14 last edited by
      #2

      Hi! I think you forgot the Q_OBJECT macro in inheritingclass. Does this really compile?

      K 1 Reply Last reply 5 Feb 2016, 15:34
      1
      • ? A Former User
        5 Feb 2016, 15:14

        Hi! I think you forgot the Q_OBJECT macro in inheritingclass. Does this really compile?

        K Offline
        K Offline
        kshegunov
        Moderators
        wrote on 5 Feb 2016, 15:34 last edited by
        #3

        @Alart
        In addition to what @Wieland wrote, Q_OBJECT is supposed to appear in the private section of the class, not as protected. So this:

        class baseclass : public QObject
        {
        protected:
            Q_OBJECT
            Q_PROPERTY(QString baseProperty READ baseProperty WRITE setBaseProperty NOTIFY basePropertyChanged)
            QString m_baseProperty;
            // ...
        };
        

        Would go like this:

        class baseclass : public QObject
        {
            Q_OBJECT
            Q_PROPERTY(QString baseProperty READ baseProperty WRITE setBaseProperty NOTIFY basePropertyChanged)
        
        protected:
            QString m_baseProperty;
            // ...
        };
        

        Read and abide by the Qt Code of Conduct

        1 Reply Last reply
        1
        • A Offline
          A Offline
          Alart
          wrote on 5 Feb 2016, 16:09 last edited by Alart 2 May 2016, 16:47
          #4

          It compiles obviously. I did "a lot of work" to provide that truncated but working example. Q_OBJECT macro is inherited from baseclass.
          You can try yourself... I can provide example for earlier versions of Qt.
          I can't add new Q_OBJECT macro, because inheritingclass does not inherit from QObject. If I add multiple inheritance it does not compile, because of ambiguous QObject.

          In fact Q_OBJECT macro can be put even in public section - it does not affect anything. Maybe that macro forces private somewhere and despite I make it protected base QObject is private?

          Edit:
          I previously worked around it by creating all properties (private or protected macros, protected variables) in base class and defining methods or whatever I needed in subclass. Then I used that in qml as base class even if it was subclass.
          But I want to define Q_PROPERTY in subclass too if it's possible, because that's more neat. I don't need to control unnecessary properties when I use base class and all special informations are stored in one class, not scattered between base and inheriting class.

          K 1 Reply Last reply 5 Feb 2016, 21:15
          0
          • A Alart
            5 Feb 2016, 16:09

            It compiles obviously. I did "a lot of work" to provide that truncated but working example. Q_OBJECT macro is inherited from baseclass.
            You can try yourself... I can provide example for earlier versions of Qt.
            I can't add new Q_OBJECT macro, because inheritingclass does not inherit from QObject. If I add multiple inheritance it does not compile, because of ambiguous QObject.

            In fact Q_OBJECT macro can be put even in public section - it does not affect anything. Maybe that macro forces private somewhere and despite I make it protected base QObject is private?

            Edit:
            I previously worked around it by creating all properties (private or protected macros, protected variables) in base class and defining methods or whatever I needed in subclass. Then I used that in qml as base class even if it was subclass.
            But I want to define Q_PROPERTY in subclass too if it's possible, because that's more neat. I don't need to control unnecessary properties when I use base class and all special informations are stored in one class, not scattered between base and inheriting class.

            K Offline
            K Offline
            kshegunov
            Moderators
            wrote on 5 Feb 2016, 21:15 last edited by kshegunov 2 May 2016, 21:15
            #5

            @Alart
            Hello,

            Q_OBJECT macro is inherited from baseclass.

            And if that were the proper way of doing it a lot of people writing Qt have gone way out of their way for nothing including it in every class that derives from QObject, whether directly or indirectly.

            I can't add new Q_OBJECT macro, because inheritingclass does not inherit from QObject. If I add multiple inheritance it does not compile, because of ambiguous QObject.

            Well, it does through baseclass, and it gives you ambiguity because Q_OBJECT is not in the private section of your base class.

            I previously worked around it by creating all properties (private or protected macros, protected variables) in base class and defining methods or whatever I needed in subclass.

            This would defeat the whole purpose of having inheritance, wouldn't it?

            Then I used that in qml as base class even if it was subclass.
            But I want to define Q_PROPERTY in subclass too if it's possible

            What you want has nothing to do with QML, but is a matter of the Qt meta-object system, and you can define properties in your derived classes, if you do that properly.

            Kind regards.

            Read and abide by the Qt Code of Conduct

            1 Reply Last reply
            1
            • C Offline
              C Offline
              Chris Kawa
              Lifetime Qt Champion
              wrote on 5 Feb 2016, 21:17 last edited by Chris Kawa 2 May 2016, 21:17
              #6

              @Alart said:

              I can't add new Q_OBJECT macro, because inheritingclass does not inherit from QObject. If I add multiple inheritance it does not compile, because of ambiguous QObject.

              inheritingclass inherits baseclass which inherits QObject, so it is a QObject already. There's no multiple inheritance present or needed here. And yes, you need Q_OBJECT macro in the inheritingclass, because it declares signals and slots. If you don't specify the Q_OBJECT macro you are limited to signals and slots declared in baseclass only, and you can't add new ones.
              Q_OBJECT macro is needed on every "level" of inheritance that adds any moc dependent features (signals, slots, properties etc.).

              1 Reply Last reply
              2
              • A Offline
                A Offline
                Alart
                wrote on 5 Feb 2016, 21:47 last edited by
                #7

                OK, I tried around it already, because this seems like a proper way.
                This is what I got, however it does not compile:

                #ifndef BASECLASS_H
                #define BASECLASS_H
                
                #include <QObject>
                
                class baseclass : public QObject
                {
                	private: // if neccesary
                		Q_OBJECT
                		Q_PROPERTY(QString baseProperty READ baseProperty WRITE setBaseProperty NOTIFY basePropertyChanged)
                		QString m_baseProperty; // this can be private or protected
                
                	public:
                		explicit baseclass(QObject *parent = 0) :
                			QObject(parent)
                			{}
                		explicit baseclass(QString baseProperty, QObject *parent = 0) :
                			QObject(parent), m_baseProperty(baseProperty)
                			{}
                
                		~baseclass() {}
                
                		QString baseProperty() const
                		{
                			return m_baseProperty;
                		}
                
                	signals:
                		void basePropertyChanged(QString baseProperty);
                
                	public slots:
                		void setBaseProperty(QString baseProperty)
                		{
                			if (m_baseProperty == baseProperty)
                				return;
                
                			m_baseProperty = baseProperty;
                			emit basePropertyChanged(baseProperty);
                		}
                };
                
                #endif // BASECLASS_H
                
                
                #ifndef INHERITINGCLASS_H
                #define INHERITINGCLASS_H
                
                #include "baseclass.h"
                
                class inheritingclass : public baseclass
                {
                		Q_OBJECT
                		Q_PROPERTY(QString newProperty READ newProperty WRITE setNewProperty NOTIFY newPropertyChanged)
                		QString m_newProperty;
                
                	public:
                		explicit inheritingclass(QObject *parent = 0) :
                			baseclass(parent)
                			{/*setParent(parent);*/}
                		explicit inheritingclass(QString baseProperty, QString newProperty, QObject *parent = 0) :
                			baseclass(baseProperty, parent), m_newProperty(newProperty)/*, m_baseProperty(baseProperty)*/
                			{/*setParent(parent);*/}
                
                		~inheritingclass() {}
                
                		QString newProperty() const
                		{
                			return m_newProperty;
                		}
                
                	signals:
                		void newPropertyChanged(QString newProperty);
                
                	public slots:
                		void setNewProperty(QString newProperty)
                		{
                			if (m_newProperty == newProperty)
                				return;
                
                			m_newProperty = newProperty;
                			emit basePropertyChanged(newProperty);
                		}
                };
                
                #endif // INHERITINGCLASS_H
                
                

                Now I'm getting:
                /home/alart/QTworek/InheritanceQobject/inheritingclass.h:14: error: undefined reference to `vtable for inheritingclass'
                The same in both constructors and destructors. I remember that problem, it had something to do with macros...

                I already tried clean and build.

                1 Reply Last reply
                0
                • K Offline
                  K Offline
                  kshegunov
                  Moderators
                  wrote on 5 Feb 2016, 21:52 last edited by kshegunov 2 May 2016, 21:52
                  #8

                  This is a very different thing altogether. Now, try without inlining your constructors, and I think you'll be good to go. Like this:

                  class baseclass : public QObject
                  {
                      Q_OBJECT
                      Q_PROPERTY(QString baseProperty READ baseProperty WRITE setBaseProperty NOTIFY basePropertyChanged)
                  
                  protected:
                      QString m_baseProperty; // this can be private or protected
                  
                  public:
                       // Define those in your cpp:
                      explicit baseclass(QObject *parent = 0); //< Don't inline this!
                      ~baseclass(); //< Don't inline this since it's virtual and virtual methods can't be inlined by the compiler anyway
                  };
                  

                  and also the same for inheritingclass.

                  Read and abide by the Qt Code of Conduct

                  1 Reply Last reply
                  1
                  • A Offline
                    A Offline
                    Alart
                    wrote on 5 Feb 2016, 22:00 last edited by
                    #9

                    OK, now it works.
                    BTW. with protected macros in baseclass it works too. But anyway I will keep it private unless I read whole documentation.

                    Thank you all.

                    1 Reply Last reply
                    0
                    • C Offline
                      C Offline
                      Chris Kawa
                      Lifetime Qt Champion
                      wrote on 6 Feb 2016, 00:38 last edited by
                      #10

                      The Q_OBJECT macro can be put in public, protected or private section and it will do the same. It doesn't matter for moc but I highly recommend to always put it at the top of your class for the following reason:

                      The Q_OBJECT macro is defined like this:

                      #define Q_OBJECT \
                      public: \
                         //stuff... \
                      private: \
                        //other stuff...
                      

                      So it's easy to make your other members private by mistake like this:

                      class Foo
                      {
                      public:
                          Q_OBJECT
                          int bar; //oh no! bar is private
                      };
                      

                      If you put the macro at the top it won't affect access declarations below:

                      class Foo
                      {
                          Q_OBJECT
                      public:
                          int bar; //yes! bar is public as intended
                      };
                      
                      1 Reply Last reply
                      0

                      2/10

                      5 Feb 2016, 15:14

                      8 unread
                      • Login

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