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. Inheritance in QT - strange problem

Inheritance in QT - strange problem

Scheduled Pinned Locked Moved Solved General and Desktop
14 Posts 5 Posters 1.0k Views 2 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.
  • T Offline
    T Offline
    TomNow99
    wrote on last edited by TomNow99
    #1

    Hi,

    A long time ago I wrote class, which inherits QRadioButton. So in "MyRadioButton" class, I have own hitButton(const QPoint &pos) , event(QEvent *e) methods. And it works.

    class MyRadioButton: public QRadioButton
    {
    ...
    }
    

    Now I have to write the same class like MyRadioButton, but for QCheckBox. So I can do something like that:

    class MyCheckBox: public QCheckBox
    {
    ...
    }
    

    But it looks bad, because of I repeat the same code in MyCheckBox and MyRadioButton ( they differs only, which they inherit )...
    I tried create class, which inherits both QRadioButton and MyRadioButton ( which inherits QAbstractButton ). But there is a problem with QObject ( I inherited it two times ). So I can't compile that. I can't virtual inherits, so... what is the best way to do that?

    JonBJ 1 Reply Last reply
    0
    • T Offline
      T Offline
      Tugdwal
      wrote on last edited by Tugdwal
      #6

      @JonB said in Inheritance in QT - strange problem:

      So far as I know, there is no way to define these overrides directly in some single class derived from both QRadioButton & QCheckBox (unless there is some clever "template"-y way of doing do, but I don't think so).

      You can totally do that with templates, by inheriting the template parameter :

      template<typename Widget>
      struct EventImpl : Widget
      {
          void event() override { }
      };
      

      You can use it like this :

      // Instance on the stack
      EventImpl<QRadioButton> w1;
      
      // Instance on the heap
      auto w2 = new EventImpl<QCheckBox>(); // Most likely in Qt
      
      // Inheritance or alias
      class RealButton : public EventImpl<QRadioButton> { /*...*/ };
      using RealButton2 = EventImpl<QRadioButton>;
      

      Obviously, interfaces and implementations for each class must be compatible with each other, or you will need to write template specializations, which defeats the purpose to avoid duplication here.

      If I remember correctly, Q_OBJECT macro cannot be used in a template, but as long as you don't need signals, it is not that much of an issue.

      JonBJ 1 Reply Last reply
      3
      • T TomNow99

        Hi,

        A long time ago I wrote class, which inherits QRadioButton. So in "MyRadioButton" class, I have own hitButton(const QPoint &pos) , event(QEvent *e) methods. And it works.

        class MyRadioButton: public QRadioButton
        {
        ...
        }
        

        Now I have to write the same class like MyRadioButton, but for QCheckBox. So I can do something like that:

        class MyCheckBox: public QCheckBox
        {
        ...
        }
        

        But it looks bad, because of I repeat the same code in MyCheckBox and MyRadioButton ( they differs only, which they inherit )...
        I tried create class, which inherits both QRadioButton and MyRadioButton ( which inherits QAbstractButton ). But there is a problem with QObject ( I inherited it two times ). So I can't compile that. I can't virtual inherits, so... what is the best way to do that?

        JonBJ Offline
        JonBJ Offline
        JonB
        wrote on last edited by
        #2

        @TomNow99
        Yes, you cannot dual-inherit from QObject. One possibility is to write common code in some non-QObject class they can share. Some useful functionality applicable to both is supplied in QButtonGroup Class, anything you want there? Otherwise what exactly are you doing in your "I repeat the same code in MyCheckBox and MyRadioButton "?

        1 Reply Last reply
        3
        • T Offline
          T Offline
          TomNow99
          wrote on last edited by TomNow99
          #3

          @JonB Thank you for answer.

          In this repeated code I have own:

          • function event(QEvent *e)
          • function hoverIn()
          • function hoverLeave()
          • function hitButton(const QPoint &pos)

          And in this functions for example, I set style for widget etc.

          JonBJ 1 Reply Last reply
          0
          • J.HilkJ Offline
            J.HilkJ Offline
            J.Hilk
            Moderators
            wrote on last edited by J.Hilk
            #4

            @JonB for some reason I kept on reading can instead of cannot and I had prepared a multi phrase argument ready to post. Reading is a virtue!

            @TomNow99 can you post more of your MyCheckBox class and the exact compiler errors you get?

            I'm sure we can help more with that information.


            Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


            Q: What's that?
            A: It's blue light.
            Q: What does it do?
            A: It turns blue.

            1 Reply Last reply
            1
            • T TomNow99

              @JonB Thank you for answer.

              In this repeated code I have own:

              • function event(QEvent *e)
              • function hoverIn()
              • function hoverLeave()
              • function hitButton(const QPoint &pos)

              And in this functions for example, I set style for widget etc.

              JonBJ Offline
              JonBJ Offline
              JonB
              wrote on last edited by
              #5

              @TomNow99
              I do not see hoverIn() or hoverLeave() as methods of any class. For event() and hitButton() these are virtual protected, so you will need to override them in your derived classes. You can either duplicate your code, or factor it out to shared functions in another module. So far as I know, there is no way to define these overrides directly in some single class derived from both QRadioButton & QCheckBox (unless there is some clever "template"-y way of doing do, but I don't think so).

              1 Reply Last reply
              1
              • T Offline
                T Offline
                Tugdwal
                wrote on last edited by Tugdwal
                #6

                @JonB said in Inheritance in QT - strange problem:

                So far as I know, there is no way to define these overrides directly in some single class derived from both QRadioButton & QCheckBox (unless there is some clever "template"-y way of doing do, but I don't think so).

                You can totally do that with templates, by inheriting the template parameter :

                template<typename Widget>
                struct EventImpl : Widget
                {
                    void event() override { }
                };
                

                You can use it like this :

                // Instance on the stack
                EventImpl<QRadioButton> w1;
                
                // Instance on the heap
                auto w2 = new EventImpl<QCheckBox>(); // Most likely in Qt
                
                // Inheritance or alias
                class RealButton : public EventImpl<QRadioButton> { /*...*/ };
                using RealButton2 = EventImpl<QRadioButton>;
                

                Obviously, interfaces and implementations for each class must be compatible with each other, or you will need to write template specializations, which defeats the purpose to avoid duplication here.

                If I remember correctly, Q_OBJECT macro cannot be used in a template, but as long as you don't need signals, it is not that much of an issue.

                JonBJ 1 Reply Last reply
                3
                • T Tugdwal

                  @JonB said in Inheritance in QT - strange problem:

                  So far as I know, there is no way to define these overrides directly in some single class derived from both QRadioButton & QCheckBox (unless there is some clever "template"-y way of doing do, but I don't think so).

                  You can totally do that with templates, by inheriting the template parameter :

                  template<typename Widget>
                  struct EventImpl : Widget
                  {
                      void event() override { }
                  };
                  

                  You can use it like this :

                  // Instance on the stack
                  EventImpl<QRadioButton> w1;
                  
                  // Instance on the heap
                  auto w2 = new EventImpl<QCheckBox>(); // Most likely in Qt
                  
                  // Inheritance or alias
                  class RealButton : public EventImpl<QRadioButton> { /*...*/ };
                  using RealButton2 = EventImpl<QRadioButton>;
                  

                  Obviously, interfaces and implementations for each class must be compatible with each other, or you will need to write template specializations, which defeats the purpose to avoid duplication here.

                  If I remember correctly, Q_OBJECT macro cannot be used in a template, but as long as you don't need signals, it is not that much of an issue.

                  JonBJ Offline
                  JonBJ Offline
                  JonB
                  wrote on last edited by
                  #7

                  @Tugdwal said in Inheritance in QT - strange problem:

                  You can totally do that with templates, by inheriting the template parameter

                  Hello and welcome.

                  I am not a template expert, I did wonder if it could maybe be done in C++ with templates, hence my comment! Thank you for informing me of how to do it, I am studying your answer to learn!

                  I am aware that in C++ struct & class are very similar. I see you have used struct EventImpl : Widget, could that have been class EventImpl : Widget?

                  So that I understand: I can see that EventImpl<QRadioButton> w1 clearly declares w1 to be an EventImpl, which has the event() override. I presume this also declares w1 as a base QRadioButton?

                  The limitation of "Q_OBJECT macro cannot be used in a template" could be a deal-breaker in certain cases, though I agree not for what the OP appears to be seeking to do here (so far at least).

                  T 1 Reply Last reply
                  1
                  • JonBJ JonB

                    @Tugdwal said in Inheritance in QT - strange problem:

                    You can totally do that with templates, by inheriting the template parameter

                    Hello and welcome.

                    I am not a template expert, I did wonder if it could maybe be done in C++ with templates, hence my comment! Thank you for informing me of how to do it, I am studying your answer to learn!

                    I am aware that in C++ struct & class are very similar. I see you have used struct EventImpl : Widget, could that have been class EventImpl : Widget?

                    So that I understand: I can see that EventImpl<QRadioButton> w1 clearly declares w1 to be an EventImpl, which has the event() override. I presume this also declares w1 as a base QRadioButton?

                    The limitation of "Q_OBJECT macro cannot be used in a template" could be a deal-breaker in certain cases, though I agree not for what the OP appears to be seeking to do here (so far at least).

                    T Offline
                    T Offline
                    Tugdwal
                    wrote on last edited by Tugdwal
                    #8

                    @JonB

                    struct and class are almost identical, but struct is public by default, so it is shorter here. I usually use it for simpler (data) structures or in examples/test code. With class, it would look something like this :

                    template<typename Widget>
                    class EventImpl : public Widget
                    {
                    protected: // Probably
                        void event() override { }
                    };
                    

                    class EventImpl : Widget is perfectly valid, but inherits privately, so public and protected members of Widget are not accessible outside of EventImpl.

                    @JonB said in Inheritance in QT - strange problem:

                    I presume this also declares w1 as a base QRadioButton?

                    I'm not sure I understand this, what do you mean by that ? w1 is a QRadioButton. It was just one way to show how to use it. I've edited my previous message, to show the different ways you could use it.

                    JonBJ 1 Reply Last reply
                    1
                    • T Tugdwal

                      @JonB

                      struct and class are almost identical, but struct is public by default, so it is shorter here. I usually use it for simpler (data) structures or in examples/test code. With class, it would look something like this :

                      template<typename Widget>
                      class EventImpl : public Widget
                      {
                      protected: // Probably
                          void event() override { }
                      };
                      

                      class EventImpl : Widget is perfectly valid, but inherits privately, so public and protected members of Widget are not accessible outside of EventImpl.

                      @JonB said in Inheritance in QT - strange problem:

                      I presume this also declares w1 as a base QRadioButton?

                      I'm not sure I understand this, what do you mean by that ? w1 is a QRadioButton. It was just one way to show how to use it. I've edited my previous message, to show the different ways you could use it.

                      JonBJ Offline
                      JonBJ Offline
                      JonB
                      wrote on last edited by
                      #9

                      @Tugdwal said in Inheritance in QT - strange problem:

                      I'm not sure I understand this, what do you mean by that

                      All good. I am making sure I understand your template statement, given that templates is one area of C++ I am not so familiar with (yes, I started as a C programmer!).

                      In my "layman's" terms I wish to confirm that

                      EventImpl<QRadioButton> w1;
                      

                      has two effects:

                      • It declares an object instance which has the void event() override { } defined in EventImpl. I get that.
                      • It also declares that object to be an instance of a QRadioButton.

                      That (the second item) may seem like a strange/damned obvious question for you familiar with templates, but I just want to verify my understanding!

                      T 1 Reply Last reply
                      1
                      • JonBJ JonB

                        @Tugdwal said in Inheritance in QT - strange problem:

                        I'm not sure I understand this, what do you mean by that

                        All good. I am making sure I understand your template statement, given that templates is one area of C++ I am not so familiar with (yes, I started as a C programmer!).

                        In my "layman's" terms I wish to confirm that

                        EventImpl<QRadioButton> w1;
                        

                        has two effects:

                        • It declares an object instance which has the void event() override { } defined in EventImpl. I get that.
                        • It also declares that object to be an instance of a QRadioButton.

                        That (the second item) may seem like a strange/damned obvious question for you familiar with templates, but I just want to verify my understanding!

                        T Offline
                        T Offline
                        Tugdwal
                        wrote on last edited by Tugdwal
                        #10

                        @JonB

                        To be correct, it is not an instance of QRadioButton then, it is an instance of EventImpl<QRadioButton>. But it inherits QRadioButton so std::vector<QRadioButton*> v; v.push_back(&w1); is valid for example. EventImpl<QCheckBox> would be completely different type, that inherits QCheckBox (ignoring that both inherits QWidget).

                        EventImpl could also have members. It is not because EventImpl is a template with QRadioButton as a parameter that it is a QRadioButton, it depends on the template implementation (which could be different for each parameter, and one could not inherit at all).

                        The template is the "model" of a class, which literally creates a new type each time we use it with different arguments. The rest is usual classes and inheritance stuff :)

                        For example, following RealButton and RealButton2, we could do the same without a template, and it would work similarly :

                        class RealButton3 : public QRadioButton
                        {
                            void event() override { }
                        };
                        
                        JonBJ 1 Reply Last reply
                        1
                        • T Tugdwal

                          @JonB

                          To be correct, it is not an instance of QRadioButton then, it is an instance of EventImpl<QRadioButton>. But it inherits QRadioButton so std::vector<QRadioButton*> v; v.push_back(&w1); is valid for example. EventImpl<QCheckBox> would be completely different type, that inherits QCheckBox (ignoring that both inherits QWidget).

                          EventImpl could also have members. It is not because EventImpl is a template with QRadioButton as a parameter that it is a QRadioButton, it depends on the template implementation (which could be different for each parameter, and one could not inherit at all).

                          The template is the "model" of a class, which literally creates a new type each time we use it with different arguments. The rest is usual classes and inheritance stuff :)

                          For example, following RealButton and RealButton2, we could do the same without a template, and it would work similarly :

                          class RealButton3 : public QRadioButton
                          {
                              void event() override { }
                          };
                          
                          JonBJ Offline
                          JonBJ Offline
                          JonB
                          wrote on last edited by JonB
                          #11

                          @Tugdwal
                          Thank you for your further interest. I hope I am not hijacking this thread (the OP has his answer now from your response), I know this should really go to the C++ Gurus sub-forum, but we are here now and hopefully this is the last request for clarification!

                          I have understood everything you have said, but for:

                          It is not because EventImpl is a template with QRadioButton as a parameter that it is a QRadioButton, it depends on the template implementation

                          This is the phrase I am struggling on. I believe I do understand this template, so I suspect it is a matter of your phrasing versus mine.

                          Given the definition of

                          template<typename Widget>
                          class EventImpl : public Widget
                          

                          it seems to me that it precisely is "because EventImpl is a template with QRadioButton as a parameter that it is a QRadioButton" (given the invocation of EventImpl<QRadioButton> w1). In the definition Widget is a variable/placeholder for the typename passed in by the caller. So it "expands to"

                          class EventImpl : public QRadioButton
                          

                          which makes it a subclass of QRadioButton. If you passed some other type as the parameter, or if this definition did not contain class EventImpl : public Widget, then it would not be a subclass of QRadioButton.

                          To summarise: this template does two things:

                          • creates a subclass of whatever class is passed in as Widget
                          • it also overrides the event() method of the passed-in class.

                          Right?

                          Now, finally: this template could theoretically be used to subclass any specified class. But because of void event() override { } the class must have virtual void event() to override. Which would fail if given some random class. But what seems "dangerous" is that the template makes no reference to QWidget. We might intend it to only accept a QWidget-derived class parameter, but if we gave it some quite unrelated class which happened to have a virtual void event() it would compile without complaint. Which seems "dangerous". Could we do anything in its definition to ensure it only accepts a QWidget-derived class parameter??

                          T 1 Reply Last reply
                          1
                          • JonBJ JonB

                            @Tugdwal
                            Thank you for your further interest. I hope I am not hijacking this thread (the OP has his answer now from your response), I know this should really go to the C++ Gurus sub-forum, but we are here now and hopefully this is the last request for clarification!

                            I have understood everything you have said, but for:

                            It is not because EventImpl is a template with QRadioButton as a parameter that it is a QRadioButton, it depends on the template implementation

                            This is the phrase I am struggling on. I believe I do understand this template, so I suspect it is a matter of your phrasing versus mine.

                            Given the definition of

                            template<typename Widget>
                            class EventImpl : public Widget
                            

                            it seems to me that it precisely is "because EventImpl is a template with QRadioButton as a parameter that it is a QRadioButton" (given the invocation of EventImpl<QRadioButton> w1). In the definition Widget is a variable/placeholder for the typename passed in by the caller. So it "expands to"

                            class EventImpl : public QRadioButton
                            

                            which makes it a subclass of QRadioButton. If you passed some other type as the parameter, or if this definition did not contain class EventImpl : public Widget, then it would not be a subclass of QRadioButton.

                            To summarise: this template does two things:

                            • creates a subclass of whatever class is passed in as Widget
                            • it also overrides the event() method of the passed-in class.

                            Right?

                            Now, finally: this template could theoretically be used to subclass any specified class. But because of void event() override { } the class must have virtual void event() to override. Which would fail if given some random class. But what seems "dangerous" is that the template makes no reference to QWidget. We might intend it to only accept a QWidget-derived class parameter, but if we gave it some quite unrelated class which happened to have a virtual void event() it would compile without complaint. Which seems "dangerous". Could we do anything in its definition to ensure it only accepts a QWidget-derived class parameter??

                            T Offline
                            T Offline
                            Tugdwal
                            wrote on last edited by
                            #12

                            @JonB

                            Everything you said is correct. And yes, there is nothing restricting to a QWidget. In most cases, it won't compile as you said, at least with override. There are complicated ways to restrict it, but I think it is possible to use a static_assert with std::is_base_of or maybe with concepts (C++20) but I'm not familiar with it.

                            1 Reply Last reply
                            2
                            • T Offline
                              T Offline
                              TomNow99
                              wrote on last edited by TomNow99
                              #13

                              @JonB @J-Hilk @Tugdwal Thank you very much!

                              But I have one more question. I try very simple code. I have:

                              1. .h file
                              template<typename T>
                              class TmpClass: public T
                              {
                              public:
                                  TmpClass();
                              };
                              
                              1. .cpp file:
                              template<typename T>
                              TmpClass<T>::TmpClass(){}
                              

                              and in other .cpp file I use it like this:

                              TmpClass<QPushButton>  someObject;
                              

                              I have error: undefined reference to `TmpClass<QPushButton>::TmpClass(). How to solve it?

                              When I have constructor body in .h file, everything is ok.

                              EDIT:
                              https://stackoverflow.com/questions/115703/storing-c-template-function-definitions-in-a-cpp-file

                              So I have:

                              template<typename T>
                              TmpClass<T>::TmpClass(){}
                              
                              template class TmpClass<QPushButton>;
                              

                              And I can compile code.

                              1 Reply Last reply
                              0
                              • SGaistS Offline
                                SGaistS Offline
                                SGaist
                                Lifetime Qt Champion
                                wrote on last edited by
                                #14

                                Hi,

                                One important thing to take into account: there are restrictions with regard to template and QObject based classes. See here for a pretty complete declaration.

                                Interested in AI ? www.idiap.ch
                                Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                                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