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
Forum Updated to NodeBB v4.3 + New Features

Subclass of subclass of qobject

Scheduled Pinned Locked Moved Solved General and Desktop
inheritancesubclassingqobject
10 Posts 4 Posters 9.3k 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.
  • 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

                      5/10

                      5 Feb 2016, 21:15

                      • Login

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