04-05-2018 01:00 PM
Hello
I am trying to create an array of objects. The objects in the array will be either based on a ChildA or ChildB class, both of which inherit from the Parent class. However, it will not be known until run time:
I have had some successful attempts building up to my requirements with:
However, when I try to put two different child objects (ChildA and ChildB) into an array of Parent objects (’04 – Inheritance with 2 different child objects.vi) I come up with the following issues:
Point 1 seems to suggest that it is not possible to link ChildA to Parent. However, ’03 – Inheritance in one object.vi’ shows a ChildA linking to the Parent input of ‘Parent.Set Name.vi’ without any coercion dots.
I would be grateful for any suggestions on where I’m going wrong. My attempts are attached.
Many thanks
RW
04-05-2018 01:41 PM
The coercion dots are expected - you have an array of parent objects, and you are putting a child object into it - it needs to be coerced to the parent object type. When you pull that object out, it returns a parent object 'type', however the child class is whats actually there. LabVIEW has no way of knowing this at edit time - to perform operations on the child class after getting it from the array, you need to cast it to the child class type. Similarly, if you would like to get rid of the coercion dots, you need to cast the child class to the parent type before putting it in the array. I am not sure if there is a big execution speed difference either way.
What is your goal here? Can you create dynamic dispatch methods for the parent that the children override when you retrieve the child classes from the array?
04-05-2018 02:16 PM
So the getParentChildNameA and getParentChildNameB can only be used by those respective and their children. Parent cannot call those since they are not defined at the parent's level. To get what I think you are after is to make the getName.vi dynamic dispatch and then override in the children classes.
04-06-2018 06:03 AM
Many thanks for the help so far.
My attempt is a simplified way of attempting to fulfil what I’m trying to achieve before applying it to the main programme.
I’m trying to have just one array of OO objects containing more than one type of object (eg ChildA and ChildB) that all inherit from the same class (eg Parent). This array will be of type ‘Parent’ as this is the common class for all the children.
Figure 1 From LabVIEW's page - http://zone.ni.com/reference/en-XX/help/371361P-01/lvconcepts/creating_classes/ )NOTE: the use of Build Array has also been used with ChildA and ChildB which results in an Array of Parent.)
The difficulty arises when I want to access a child function (eg setChildNameA) when I use the ‘Index Array’ function. Even though a ChildA object has been stored a Parent object is returned; this Parent cannot access ‘setChildNameA’. This seems quite obvious, but I thought LabVIEW coped with this method of inheritance behind the scenes thus allowing the Child functions to be accessed.
I have placed a probe at a couple of locations as follows:
Location of probe |
Probe Display |
Comments |
Output of ‘SET CHILD A NAME’ |
The contents of both ‘NameParent’ and ‘NameChildA’ are as expected in this situation. |
|
Output of ‘Index Array’ |
The data for ‘NameParent’ is as expected (ie an empty string).
However, this only returns the data available for the Parent, whereas data for the Child is also needed. |
|
|
|
|
The above suggests that once the Child object is inserted into the array only the Parent’s data is seen even though the ‘Actual Data Type’ is a Child.
Thanks for the idea of using the dynamic dispatch approach. However:
Am I right in thinking that what I want to achieve is not possible in LabVIEW?
Thanks
RW
04-06-2018 06:43 AM
@rw2018 wrote:My attempt is a simplified way of attempting to fulfil what I’m trying to achieve before applying it to the main programme.
I’m trying to have just one array of OO objects containing more than one type of object (eg ChildA and ChildB) that all inherit from the same class (eg Parent). This array will be of type ‘Parent’ as this is the common class for all the children.
The difficulty arises when I want to access a child function (eg setChildNameA) when I use the ‘Index Array’ function. Even though a ChildA object has been stored a Parent object is returned; this Parent cannot access ‘setChildNameA’. This seems quite obvious, but I thought LabVIEW coped with this method of inheritance behind the scenes thus allowing the Child functions to be accessed.
The above suggests that once the Child object is inserted into the array only the Parent’s data is seen even though the ‘Actual Data Type’ is a Child.
Thanks for the idea of using the dynamic dispatch approach. However:
- As I’m wanting two different objects in the array wouldn’t the Parent still be the common class using this approach?Wouldn't this mean that I have the same problem of the Parent being returned from the Index Array even though ChildA or ChildB has been inserted into the array?
Am I right in thinking that what I want to achieve is not possible in LabVIEW?
Thanks
RW
Hi,
if I understand correctly what you are trying to achieve, you have a lkittle misunderstanding of dynamic dispatching - but what you want is actually possible!
When different child objects are returned from your array they will call their own method e.g. "setname.vi" even if you can see only the parent method on your block diagram. But to make this dynamic dispatch possible you need 3 different VIs with the same name(!). Just add a "setname" method to your parent class.
I hope that helps.
04-06-2018 06:46 AM
@rw2018 wrote:
The above suggests that once the Child object is inserted into the array only the Parent’s data is seen even though the ‘Actual Data Type’ is a Child.
Thanks for the idea of using the dynamic dispatch approach. However:
- As I’m wanting two different objects in the array wouldn’t the Parent still be the common class using this approach?Wouldn't this mean that I have the same problem of the Parent being returned from the Index Array even though ChildA or ChildB has been inserted into the array?
No and no. Even though the wire type is of Parent, Child's data is still there. You can just only use methods that have been defined by Parent. When you have a Dynamic Dispatch method, the parent is defining the interface of that method. What happens inside of that method is based on what object it was initialized as. If a child overrides the method, then the child's method will run. This is the heart of Inheritance and Polymorphism.
04-06-2018 07:37 AM
Thanks for the feedback.
@crabman wrote:
Just add a "setname" method to your parent class.
@crossrulz wrote:
You can just only use methods that have been defined by Parent. .
As I understand it then, if I want to create a new function in a Child then I also need to define it with the same name in the Parent but as a dynamic dispatch and then use the Parent's version of the function in the VIs?
04-06-2018 07:48 AM
@rw2018 wrote:
Thanks for the feedback.
@crabman wrote:
Just add a "setname" method to your parent class.
@crossrulz wrote:
You can just only use methods that have been defined by Parent. .As I understand it then, if I want to create a new function in a Child then I also need to define it with the same name in the Parent but as a dynamic dispatch and then use the Parent's version of the function in the VIs?
Yes, that will get you what you want, but may not be the best design choice.
Is child B also going to have its own override of this method? What about child x? Or are you just putting it in the parent class because child A needs it? If thats the case, I would rethink your design.
04-06-2018 08:39 AM
@paul.r wrote: @paul.ross
Is child B also going to have its own override of this method? What about child x? Or are you just putting it in the parent class because child A needs it? If thats the case, I would rethink your design.
Yes, eventually, ChildA will have functions that ChildB won't have and visa versa. In that instance, these would only put into Parent because the child needed it. What sort of redesign would you suggest?
04-06-2018 08:53 AM
@rw2018 wrote:
@paul.r wrote: @paul.ross
Is child B also going to have its own override of this method? What about child x? Or are you just putting it in the parent class because child A needs it? If thats the case, I would rethink your design.
Yes, eventually, ChildA will have functions that ChildB won't have and visa versa. In that instance, these would only put into Parent because the child needed it. What sort of redesign would you suggest?
Well, you are designing your parent based on the details of children - this is a violation of the dependency inversion/Liskov substitution principles. If you do this for every case where a unique child needs something in the parent, your parent class will end up with a big mess of methods that arent relevant to all children.
What is your end goal? If I store a bunch of classes in an array, its usually because I have a set of operations I want to perform that are common to all child classes that would be in the array. I don't know what your application looks like and what you are doing with the array, but if you have specific operations that are only applicable to a child class, cast the object to the child class. However, as soon as you do that, you are kind of assuming that you will always place child class x in index y of the array.. which isnt a great design either..