passing arguments to C++ functions
-
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...
@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. -
@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.@Christian-Ehrlicher I have appended a new paragraph to my earlier response as a result of this conversation with you.
-
@Christian-Ehrlicher I have appended a new paragraph to my earlier response as a result of this conversation with you.
@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.)
-
@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.)
@mzimmers
Please re-read the discussion. The point is that if you have a formal parameterEquipment e
this has to be passed in as a copy by value to a temporary of base-typeEquipment
. You pass avspStruct
as your parameter, but that does not get through to the function, it gets just anEquipment
copy. And soe.data()
isEquipment::data()
, thevspStruct
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, notEquipment e
. I believe @Axel-Spoerl & @Christian-Ehrlicher have said QML does not prevent you from doing so. -
@mzimmers
Please re-read the discussion. The point is that if you have a formal parameterEquipment e
this has to be passed in as a copy by value to a temporary of base-typeEquipment
. You pass avspStruct
as your parameter, but that does not get through to the function, it gets just anEquipment
copy. And soe.data()
isEquipment::data()
, thevspStruct
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, notEquipment e
. I believe @Axel-Spoerl & @Christian-Ehrlicher have said QML does not prevent you from doing so. -
@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.@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. -
@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:
Notice that e is still an Equipment. By contrast, listEntry is a (pointer to a) Vsp.Or, am I still not understanding you?
-
@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:
Notice that e is still an Equipment. By contrast, listEntry is a (pointer to a) Vsp.Or, am I still not understanding you?
So, after a little trial and error, here's where I stand:
- 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.
- 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:
My cast doesn't seem to have had the desired effect of "recapturing" the subclass. Perhaps I'm doing something wrong with this?
- 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.
-
So, after a little trial and error, here's where I stand:
- 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.
- 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:
My cast doesn't seem to have had the desired effect of "recapturing" the subclass. Perhaps I'm doing something wrong with this?
- 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.
-
@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.
@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.
-
M mzimmers has marked this topic as solved on