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
Qt 6.11 is out! See what's new in the release blog

Inheritance in QT - strange problem

Scheduled Pinned Locked Moved Solved General and Desktop
14 Posts 5 Posters 1.1k 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 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