OOP question
BlitzMax Forums/BlitzMax Beginners Area/OOP question
| ||
One advantage I can see to OOP is you can make everything a derivitive of a base class, in this case "tEngineNode". If your player class then has a "target" value of another entity, you can supply it with any kind of type, since they are all derivitives of the tEngineNode. However, when I try this, I am unable to recover the "speed" value.Type tEngineNode EndType Type tPlayer Extends tEngineNode Field target:tenginenode EndType Type tVehicle Extends tEngineNode Field speed#=100 Field target:tenginenode EndType player:tplayer=New tplayer vehicle:tvehicle=New tvehicle player.target=vehicle Notify player.target.speed |
| ||
Target is marked as a tEngineNode, not a tVehicle, so when you pass vehicle to target, it gets downcasted to a tEngineNode. So, before you can get speed, you have to cast it as a tVehicle.player:tplayer=New tplayer vehicle:tvehicle=New tvehicle player.target=vehicle vehicle = Null ' Just to ingrain the fact that we are not using the old reference vehicle = tVehicle( player.target ) If vehicle Then Notify vehicle.speed However, this is a rather inconvenient way to get something. After all, you don't want to cast and check each time. My personal preference is to use messaging. E.g., Const MSG_SPEED% = $00000001 Type tEngineNode Method SendMessageF:Float( msg:Int ) Return 0 End Method Field target:tenginenode EndType Type tPlayer Extends tEngineNode EndType Type tVehicle Extends tEngineNode Field speed#=100 Method SendMessageF:Float( msg:Int ) Select msg Case MSG_SPEED Return speed End Select Return 0 End Method EndType player:tplayer=New tplayer vehicle:tvehicle=New tvehicle player.target=vehicle Notify player.target.SendMessageF( MSG_SPEED ) All Objects have a default SendMessage method that you can override (not overload), it's under Language Reference->Objects in the documentation. The above example uses a custom method in the base class to return a float instead of an object. |
| ||
Your first example is just as inconvenient as the old Blitz method:Type tplayer Field target End Type Type tvehicle Field speed# End Type player.tplayer=New tplayer vehicle.tvehicle=New tvehicle player\target=Handle(vehicle) vehicle.tvehicle=Object.tvehicle(vehicle) If vehicle<>Null Notify vehicle\speed Your second example looks like hell. And finally, here it is with my old system I used to write 3D World Studio: player=CreatePlayer() vehicle=CreateVehicle() SetPlayerTarget player,vehicle target=PlayerTarget(player) If ObjectClass(target)=CLASS_VEHICLE Notify VehicleSpeed(target) The big advantage with mine is I can do things like this: SelectObjectClass(PlayerTarget(player)) Case CLASS_MONSTER Case CLASS_FLARE EndSelect Although OOP could do this: Type tEngineNode Field target:tenginenode Method Update() EndMethod EndType Type tPlayer Extends tEngineNode Method Update() EndMethod EndType Type tVehicle Extends tEngineNode Method Update() Notify 1 EndMethod EndType player:tplayer=New tplayer vehicle:tvehicle=New tvehicle player.target=vehicle player.target.update() The fact that I can't call player.target.speed is really putting me off of types. |
| ||
Would this work ? vehicle:tvehicle=New tvehicle player.target=vehicle . . en:tEngineNode = player.target Notify en.speed [edit: oop(s), that wouldn't work. see my post below about casting] This works: 'casting If tvehicle(player.target) Then Notify tvehicle(player.target).speed# EndIf |
| ||
No. |
| ||
Do it like this:Type tEngineNode Field target:tEngineNode Field vehicle:tVehicle Field player:tPlayer EndType Type tPlayer Extends tEngineNode Method New() player=Self EndMethod EndType Type tVehicle Extends tEngineNode Field speed#=100 Method New() vehicle=Self EndMethod EndType player:tplayer=New tplayer vehicle:tvehicle=New tvehicle player.target=vehicle Notify player.target.vehicle.speed |
| ||
Is it possible to have a generic :object?Type tEngineNode Field target:tEngineNode Field subobject:Object EndType |
| ||
Is it possible to have a generic :object? Yes. All objects implicitly extend the Object class. |
| ||
What you need is casting:Type tEngineNode EndType Type tPlayer Extends tEngineNode Field target:tengineNode EndType Type tVehicle Extends tEngineNode Field speed#=100 Field target:tenginenode EndType player:tplayer=New tplayer vehicle:tvehicle=New tvehicle player.target=vehicle 'here is casting. If tvehicle(player.target) Then Notify tvehicle(player.target).speed# EndIf Bare in mind that casting is either powerful and dangerous. if you attempt to use it against a wrong class (that is, type), then you get an error. That's why you should check first if the player.target can be 'casted' to a tvehicle type: If tvehicle(player.target) Another thing. Classes are powerful, but you should use it wisely. If you have classes that inherits (extends in BMax) from a main class (in your example, tEngineNode), and share the same variable (like the speed# above), then you may put that variable in the main class, instead of spreading it in other classes. That way you don't even need any casting later. Good planned classes may save lots of work and time in the middle-long run of code development. Sergio. |