Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. passing arguments to C++ functions
Forum Updated to NodeBB v4.3 + New Features

passing arguments to C++ functions

Scheduled Pinned Locked Moved Solved QML and Qt Quick
17 Posts 5 Posters 2.5k 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.
  • JonBJ JonB

    @mzimmers
    A couple of observations from me. Remember I know nothing about QML, only about C++ in general.

    First, like @Axel-Spoerl said the first approach which comes to mind is qobject_cast<> or dynamic_cast<>. The former can only only be used on a pointer. The latter, however, as discussed in a recent thread on this forum can also be used on a non-pointer value type, though I was not aware of this until that thread.

    So if your issue is over it being passed as a Equipment e rather than a vspStruct vsp you can still go dynamic_cast<vspStruct>(e) (note no pointer). The only "wrinkle" is that while on a pointer the dynamic cast can return nullptr if it is not of the required type, which is easy to test for, in the latter, value type case there is no return value possible to indicate this. So instead C++ raises a runtime exception, std::bad_cast, in such a case. To detect this you would have to wrap the call in a C++ try ... catch, but that is doable.

    Next, untested but I don't see why you cannot take the object's address to produce a pointer. So dynamic_cast<vspStruct *>(&e) should be usable, and would avoid needing to test for an exception as it can return nullptr.

    Finally, since you are in charge of the code for Equipment & vspStruct (right?) have you considered introducing some virtual methods (even helper function if useful), where vspStruct and other subclasses override them, for your convenience? When you call a virtual method on an object it executes the overridden definition for the actual instance specific-type, even if the code only has a variable of the base type. So in your case with formal parameter Equipment e calling e.virtualMethod() will execute vspStruct.virtualMethod() if actual parameter for e is a vspStruct instance. The advantage here is that you do not have to do any casting of Equipment to vspStruct or know whether the instance passed is some specific sub-classed instance. This may be useful to bear in mind whatever your solution.

    [I stand to be corrected by a C++ expert if anything I have said here is incorrect, especially about passing a derived type as a value type rather than as a pointer.]

    [EDIT After conversations with C++ expert @Christian-Ehrlicher, your attempt to pass a vspStruct instance actual parameter to a function receiving an Equipment e formal parameter, and anything I said relying on that, is incorrect/unusable. That code must make a copy (because neither pointer not reference) but would only call Equipment's copy constructor, not vspStructs. Which means what you receive is no longer a vspStruct and so nothing can make it one or allow you to call/access anything in vspStruct on it. See how @Christian-Ehrlicher has confirmed this in his latest answer later on below.]

    Axel SpoerlA Offline
    Axel SpoerlA Offline
    Axel Spoerl
    Moderators
    wrote on last edited by
    #7

    Thank you @JonB, for looking into the issue so much deeper than I did yesterday evening! I actually like the virtual method approach, which could be used to identify if an Equipment is actually a vspStruct and hence, casting would work. It could even be used, to make the casting redundant at all.

    Software Engineer
    The Qt Company, Oslo

    1 Reply Last reply
    0
    • mzimmersM mzimmers

      Hi all -

      I'm not sure whether this is a QML question or a C++ question, but I figured I start here.

      I have a C++ model that uses a list of pointers to objects. These objects may be members of a parent class (Equipment) or of a subclass (eg Vsp).

      I need to perform some activities that are more appropriately performed in C++ than in QML/JS. My problem is, when I pass an argument that is a subclass, I don't know how to get my C++ function to recognize that it's a subclass. A QML call might look like:

      ColumnLayout {
          property vspStruct vsp // vspStruct is the subclass
          ...
          onButtonClicked: {
              if (equipmentModel.changesExist(vsp)) {
              ...
      

      And the C++ routine is:

      bool EquipmentModel::changesExist(Equipment e) {
      ...
      

      As you can see, this isn't going to work, because the argument is treated as a member of the parent class, but I need to look at properties of the subclass.

      So...is there something that can be done on the QML side where I can pass this a pointer or a reference or something that would allow me to cast it in the C++ function?

      Any other ideas are equally welcome. Thanks...

      Christian EhrlicherC Offline
      Christian EhrlicherC Offline
      Christian Ehrlicher
      Lifetime Qt Champion
      wrote on last edited by
      #8

      @mzimmers said in passing arguments to C++ functions:

      bool EquipmentModel::changesExist(Equipment e) {

      This is creating a copy by calling the Equipment copy ctor so no chance to do any cast to vspStruct.
      Pass it by const ref or pointer - everything else will not work.

      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
      Visit the Qt Academy at https://academy.qt.io/catalog

      JonBJ 2 Replies Last reply
      2
      • Christian EhrlicherC Christian Ehrlicher

        @mzimmers said in passing arguments to C++ functions:

        bool EquipmentModel::changesExist(Equipment e) {

        This is creating a copy by calling the Equipment copy ctor so no chance to do any cast to vspStruct.
        Pass it by const ref or pointer - everything else will not work.

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

        @Christian-Ehrlicher I have appended a new paragraph to my earlier response as a result of this conversation with you.

        mzimmersM 1 Reply Last reply
        0
        • JonBJ JonB

          @Christian-Ehrlicher I have appended a new paragraph to my earlier response as a result of this conversation with you.

          mzimmersM Offline
          mzimmersM Offline
          mzimmers
          wrote on last edited by
          #10

          @JonB thanks for the in-depth response. I've actually tried the virtual method approach you suggest, but I must be doing something wrong:

          // equipment.h
              virtual QVariant data(int role);
          // vsp.h
              QVariant data(int role) override;
          // equipmentModel.cpp
          bool EquipmentModel::changesExist(Equipment e) {
              e.data(256); // calls the method in equipment.h, not vsp.h.
              ...
          

          BTW: my equipment struct isn't abstract; I actually use it for some items. I'm not sure whether this makes a difference.)

          JonBJ 1 Reply Last reply
          0
          • mzimmersM mzimmers

            @JonB thanks for the in-depth response. I've actually tried the virtual method approach you suggest, but I must be doing something wrong:

            // equipment.h
                virtual QVariant data(int role);
            // vsp.h
                QVariant data(int role) override;
            // equipmentModel.cpp
            bool EquipmentModel::changesExist(Equipment e) {
                e.data(256); // calls the method in equipment.h, not vsp.h.
                ...
            

            BTW: my equipment struct isn't abstract; I actually use it for some items. I'm not sure whether this makes a difference.)

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

            @mzimmers
            Please re-read the discussion. The point is that if you have a formal parameter Equipment e this has to be passed in as a copy by value to a temporary of base-type Equipment. You pass a vspStruct as your parameter, but that does not get through to the function, it gets just an Equipment copy. And so e.data() is Equipment::data(), the vspStruct original has got lost.

            This would not happen if your method were either of

            bool EquipmentModel::changesExist([const] Equipment *e)    // pointer
            bool EquipmentModel::changesExist([const] Equipment &e)    // reference
            

            Then it would pass and receive your original vspStruct. You need to change over to one of these, not Equipment e. I believe @Axel-Spoerl & @Christian-Ehrlicher have said QML does not prevent you from doing so.

            M 1 Reply Last reply
            0
            • JonBJ JonB

              @mzimmers
              Please re-read the discussion. The point is that if you have a formal parameter Equipment e this has to be passed in as a copy by value to a temporary of base-type Equipment. You pass a vspStruct as your parameter, but that does not get through to the function, it gets just an Equipment copy. And so e.data() is Equipment::data(), the vspStruct original has got lost.

              This would not happen if your method were either of

              bool EquipmentModel::changesExist([const] Equipment *e)    // pointer
              bool EquipmentModel::changesExist([const] Equipment &e)    // reference
              

              Then it would pass and receive your original vspStruct. You need to change over to one of these, not Equipment e. I believe @Axel-Spoerl & @Christian-Ehrlicher have said QML does not prevent you from doing so.

              M Offline
              M Offline
              mpergand
              wrote on last edited by
              #12

              @JonB
              I confirm, i 've just made a test, it doesn't work with a copy passed by value.

              1 Reply Last reply
              0
              • Christian EhrlicherC Christian Ehrlicher

                @mzimmers said in passing arguments to C++ functions:

                bool EquipmentModel::changesExist(Equipment e) {

                This is creating a copy by calling the Equipment copy ctor so no chance to do any cast to vspStruct.
                Pass it by const ref or pointer - everything else will not work.

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

                @Christian-Ehrlicher said in passing arguments to C++ functions:

                This is creating a copy by calling the Equipment copy ctor so no chance to do any cast to vspStruct.
                Pass it by const ref or pointer - everything else will not work.

                1 Reply Last reply
                0
                • mzimmersM Offline
                  mzimmersM Offline
                  mzimmers
                  wrote on last edited by mzimmers
                  #14

                  @JonB said in passing arguments to C++ functions:

                  You need to change over to one of these, not Equipment e. I believe @Axel-Spoerl & @Christian-Ehrlicher have said QML does not prevent you from doing so.

                  Well, I tried that, and this is the result:
                  Screenshot 2023-12-09 074400.png
                  Notice that e is still an Equipment. By contrast, listEntry is a (pointer to a) Vsp.

                  Or, am I still not understanding you?

                  mzimmersM 1 Reply Last reply
                  0
                  • mzimmersM mzimmers

                    @JonB said in passing arguments to C++ functions:

                    You need to change over to one of these, not Equipment e. I believe @Axel-Spoerl & @Christian-Ehrlicher have said QML does not prevent you from doing so.

                    Well, I tried that, and this is the result:
                    Screenshot 2023-12-09 074400.png
                    Notice that e is still an Equipment. By contrast, listEntry is a (pointer to a) Vsp.

                    Or, am I still not understanding you?

                    mzimmersM Offline
                    mzimmersM Offline
                    mzimmers
                    wrote on last edited by
                    #15

                    So, after a little trial and error, here's where I stand:

                    1. according to @Axel-Spoerl, since my Equipment class isn't derived from QObject, QML is limited to passing it as a const reference to C++ functions.
                    2. There are (at least) 3 options for coding my C++ function:
                    • bool EquipmentModel::changesExist(Equipment e)
                    • bool EquipmentModel::changesExist(const Equipment *e)
                    • bool EquipmentModel::changesExist(const Equipment &e)
                      As @Christian-Ehrlicher pointed out, the first option won't work for me. The second option produces a run time error about incompatible JS arguments. The last option builds and runs, but the behavior is somewhat baffling:
                      Screenshot 2023-12-11 070800.png
                      My cast doesn't seem to have had the desired effect of "recapturing" the subclass. Perhaps I'm doing something wrong with this?
                    1. Interestingly enough, if I do a direct JS comparison in my QML instead of calling this routine, it works. So, if my assumptions are correct, it's really the QML-to-C++ interface that is the limitation here, and this is probably due to the fact that I'm trying to use a non-QObject based struct.

                    Unless someone has any QML-based ideas on this, I'm going to consider the matter closed. I do have more questions, but they're more appropriate for the C++ forum.

                    Thanks to everyone who helped with this.

                    JonBJ 1 Reply Last reply
                    0
                    • mzimmersM mzimmers

                      So, after a little trial and error, here's where I stand:

                      1. according to @Axel-Spoerl, since my Equipment class isn't derived from QObject, QML is limited to passing it as a const reference to C++ functions.
                      2. There are (at least) 3 options for coding my C++ function:
                      • bool EquipmentModel::changesExist(Equipment e)
                      • bool EquipmentModel::changesExist(const Equipment *e)
                      • bool EquipmentModel::changesExist(const Equipment &e)
                        As @Christian-Ehrlicher pointed out, the first option won't work for me. The second option produces a run time error about incompatible JS arguments. The last option builds and runs, but the behavior is somewhat baffling:
                        Screenshot 2023-12-11 070800.png
                        My cast doesn't seem to have had the desired effect of "recapturing" the subclass. Perhaps I'm doing something wrong with this?
                      1. Interestingly enough, if I do a direct JS comparison in my QML instead of calling this routine, it works. So, if my assumptions are correct, it's really the QML-to-C++ interface that is the limitation here, and this is probably due to the fact that I'm trying to use a non-QObject based struct.

                      Unless someone has any QML-based ideas on this, I'm going to consider the matter closed. I do have more questions, but they're more appropriate for the C++ forum.

                      Thanks to everyone who helped with this.

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

                      @mzimmers said in passing arguments to C++ functions:

                      bool EquipmentModel::changesExist(const Equipment &e)

                      That is the only correct one of the three.

                      If you want you can discuss elsewhere whether/how to achieve what you want.

                      mzimmersM 1 Reply Last reply
                      1
                      • JonBJ JonB

                        @mzimmers said in passing arguments to C++ functions:

                        bool EquipmentModel::changesExist(const Equipment &e)

                        That is the only correct one of the three.

                        If you want you can discuss elsewhere whether/how to achieve what you want.

                        mzimmersM Offline
                        mzimmersM Offline
                        mzimmers
                        wrote on last edited by
                        #17

                        @JonB if I understood @Axel-Spoerl correctly, the pointer version would work if I derived my struct from QQuickItem, but that's not a desired option at this time.

                        And yes, I think it's time to move this discussion to the C++ forum. Thanks again for the help.

                        1 Reply Last reply
                        0
                        • mzimmersM mzimmers has marked this topic as solved on

                        • Login

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