MartinMcD Posted September 3, 2012 Report Share Posted September 3, 2012 Hello all, Well I'm getting there with the whole OO thing but I now find myself confused again, if someone could help I'd really appreciate it. My example scenario... -I initially create a Motorbike class. Into the class private data I add the property NumberOfWheels and set the default value to 2. Now, whenever I drop a Motorbike object constant on to my block diagram or use the 'Get LV Class Default Value' I have a motorbike object with the right number of wheels. -I create a Car class and realise that it also needs a NumberOfWheels property which I create and set the default value to 4. - I realise I can create a Vehicle parent class which these 2 classes can inherit from. I recognise all my vehicles have wheels so I move the NumberOfWheels property up to the Vehicle class. I set the default value to 1. Now, whenever I drop a motorbike object constant on to my block diagram I will find that if I did nothing else my motorbike only has one wheel. So I create an Init method in Vehicle set to must override. Instead of dropping a Motorbike constant I instead drop the Motorbike override of Vehicle Init. This init function calls the Vehicle 'Write NumberOfWheels' accessor passing a value of 2. Every child class has to do the same. I'm just wondering if this is the right way of going about it please? What I mean is that before I set up the inheritance I could be sure that every motorbike object would have the right number of wheels. Now I need to rely on the init function to change the value to something sensible. My default class data for a motorbike is now no longer stored in the private data (and so can't be read in using the Get LV Class Default Value vi) but in an init vi. I can't think of another way of doing it so I'm thinking I might be worrying about nothing but it'd be great to check. Thank you, Martin Quote Link to comment
Daklu Posted September 4, 2012 Report Share Posted September 4, 2012 Generally speaking, yes, you have it correct. However, many of us have adopted a functionally similiar but slightly different implementation pattern. Instead of creating an overridable Init method for each class, I suggest creating a custom, non-overridable, Create method for each class. Where you would previously drop the class constant on the block diagram and wire it to the Init method when you need an instance of the class, now you'll just drop the Create method. The Create method gives you a place to properly initialize the class' internal data fields. Here's an example of a very simple Create method from one of my projects. In this case the object create method has one input parameter, a TTB File object, and initializes an internal data field before passing the fully configured object out to be used by the calling code. Notes: * To avoid name conflicts with child classes, I always append the class name to my create methods. (i.e. "Create Motorbike" or "Create Car.") * When starting out I suggest not having an input terminal for the class being created. It has uses in more complex scenarios, but you can do quite a lot without them and it's easier to understand when you're starting out. Quote Link to comment
MartinMcD Posted September 4, 2012 Author Report Share Posted September 4, 2012 (edited) Ah-ha, thank you very much for that. So my image below would be the correct way of setting up a motorbike vehicle - calling the parent accessor to set the number of wheels? Also, I do use the 'Get LV Class Default Value.vi' quite a bit to dynamically load classes from disk as required. Am I correct that in this case we'd have to use a dymanic dispatch init method to set the object properties to the required values? I can't see how else I'd do it because the default class data won't have the correct values for the data inherited from the parent class - the number of wheels in this case. Thanks, Martin Setting up the object where some property is defined in the parent: Loading from file, calling dynamic dispatch init method: Edited September 4, 2012 by MartinMcD Quote Link to comment
jgcode Posted September 4, 2012 Report Share Posted September 4, 2012 Here is a link to a thread on this topic that you may like to read: http://lavag.org/topic/14759-can-i-override-private-data/ 2 Quote Link to comment
drjdpowell Posted September 4, 2012 Report Share Posted September 4, 2012 As a different take on it, if “Number of Wheels” is a constant of the class (2 for Motorbike, etc.) then it shouldn’t be a “data” item at all. It should be an overridable method that returns the constant value: Car.lvclass would have a similar override with the constant 4. Use this method wherever you need the number of wheels. — James Added later: if the number of wheels isn’t a constant, you can still have different defaults. Make the default number of wheels “-1”, and have the methods return the default value for the class only if the data item is “-1”. That way you can change the value if you want, but the default exists without needing an “Init” method. Quote Link to comment
Daklu Posted September 4, 2012 Report Share Posted September 4, 2012 Here is a link to a thread on this topic that you may like to read: http://lavag.org/topic/14759-can-i-override-private-data/ I'm glad you posted that Jon. ~6 weeks ago I ran into a situation with LapDog.Messaging where I wished I had given it class input terminals and I immediately thought of that thread. It should be an overridable method that returns the constant value: I've done that before, but ultimately abandoned it for a couple reasons: 1. I prefer to have all code related to object initialization (or default values) contained in a single place. 2. It's nice to be able to see the values when I probe the class wire. The one place I can think of where it might make technical sense to return a constant in the method is if the constant is very large and you're concerned about memory copies. So my image below would be the correct way of setting up a motorbike vehicle - calling the parent accessor to set the number of wheels? Yep. Also, I do use the 'Get LV Class Default Value.vi' quite a bit to dynamically load classes from disk as required. Am I correct that in this case we'd have to use a dymanic dispatch init method to set the object properties to the required values? I can't see how else I'd do it because the default class data won't have the correct values for the data inherited from the parent class - the number of wheels in this case. I'll have to think about this for a bit. It's 3am and my brain is protesting the lack of sleep. (Couldn't you just dynamically call the class' Creator?) Quote Link to comment
MartinMcD Posted September 4, 2012 Author Report Share Posted September 4, 2012 Thanks all, I'm having a good read through... Quote Link to comment
Aristos Queue Posted September 4, 2012 Report Share Posted September 4, 2012 Martin: a slight variation on drjdpowell's suggestion, which works if it is not a constant: Add the value and a Boolean "has been set?". The data accessor VI that returns the value first checks the Boolean. If the value has never been set, it returns the default for that class (call the dynamic dispatch function exactly as described by drjdpowell above). If it has been set, it returns whatever value has been stored into the object. Quote Link to comment
drjdpowell Posted September 4, 2012 Report Share Posted September 4, 2012 I've done that before, but ultimately abandoned it for a couple reasons: 1. I prefer to have all code related to object initialization (or default values) contained in a single place. 2. It's nice to be able to see the values when I probe the class wire. Depends how many default values you have. If you’re carrying along a dozen constants you’ll have complex “Create” methods and generic probes which are well nigh unreadable. Note that a custom probe can call the classes methods in order to display the values. I usually put a method called “Text description” in any class hierarchy that gives a clear-english description of only the important information of the object; this makes making custom probes or other debug or logging tools easier. Martin: a slight variation on drjdpowell's suggestion, which works if it is not a constant: Add the value and a Boolean "has been set?". The data accessor VI that returns the value first checks the Boolean. If the value has never been set, it returns the default for that class (call the dynamic dispatch function exactly as described by drjdpowell above). If it has been set, it returns whatever value has been stored into the object. Yes. And that method will work with parameters that don’t have non-physical values (like −1 wheels). Quote Link to comment
Martin D Posted May 5, 2019 Report Share Posted May 5, 2019 (edited) Sorry to jump in to this so topic so many years later, but I am new to OOP, and have been struggling with the same question. The alternative solution I came up with was to store the class data in the children instead of the parent. That way each child can have its own unique default settings, and the object can be dropped onto the diagram without needing a separate "creator" vi. The class data is accessed by creating override methods in the children. Anything inherently wrong with this approach? Edited May 5, 2019 by Martin D Quote Link to comment
Aristos Queue Posted June 23, 2019 Report Share Posted June 23, 2019 MartinD: no, nothing wrong with that, but I usually only use that approach when the value is a computed value that needs different data storage. For example, “determinant” of a matrix... sparse matrix and dense matrix have different data storage, and determinant is computed differently for each type. But it works fine in your case, too. It’s nice if some classes have it as a variable (gets stored per object), but other classes it is constant for all objects of the class, so the method can just return a constant and not burden every object with that bit of data. Quote Link to comment
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.