BlitzCoder Essentials
•
Home Page
•
About BlitzCoder
•
Contributors
•
Terms of Use
•
Email Us
Main Areas
•
BlitzCoder Chat
•
Discussions
•
Articles/Tutorials
•
Code Database
•
Link Database
•
Showcase Area
•
Worklogs
•
Competitions
Special Areas
•
Undocumented
Other Blitz Sites
•
Blitz Basic Home
•
Blitz Showcase
•
BlitzPlay Library
Forum Login
Username:
Password:
•
Register Now!
BlitzCoder Code Archives Page
Main Codes Page
"Object and Handle (polymorphism)"
, by thechange
How to use Object and Handle commands in general and creating your own (hardcoded) polymorphic functions, being able to handle multiple object structures in a single call (!).
Code
;------------------------------------------------------------------------------; ; Introduction: ; Using the Object and Handle commands you can convert from Pointer to Address ; and back, making it possible to create (hardcoded) polymorphic functions, ; handling multiple types of objects passed as parameter. ; The short explanation: ; The Handle( Pointer ) function returns the address of the Object pointer to an ; existing object or instance of a type declaration. ; The Object.Type( Address ) keyword returns a pointer to an object of the ; specified Type at the specified Address. ; E.g. typecasting to and from pointer from and to address. ; The long explanation: ; Imagine a simple Type declaration. Type Struct Field Value% End Type ; We'll need a pointer to and an address of an existing (or unexisting) object ; of the same type. Local PointerToStruct.Struct Local AddressOfPointer% ; Let's create a new object and fill it with something useful. PointerToStruct = New Struct PointerToStruct\Value = 2147483647 ; Now we can convert the pointer to an address and nullify it, making it ; inaccessible. AddressOfPointer = Handle( PointerToStruct ) PointerToStruct = Null ; And to make it accessible again, we reverse the process and zero the address. PointerToStruct = Object.Struct( AddressOfPointer ) AddressOfPointer = 0 ; A pointer can only be used to create, delete or modify the object. One will ; need its address to know where it is exactly. You can only compare pointers to ; pointers and pointers to Null, for a pointer does not contain a value. ; One can pass a pointer to a function as parameter but only if one already ; knows the Type. One cannot pass an unidentified pointer to a function. Which ; also goes for returning pointers. ; However one *can* pass an address to a function, because an address *is* an ; integer variable. So giving an example is very similar to the things already ; described above. Function Create_Struct( New_Value% ) Local Pointer_To_Struct.Struct Pointer_To_Struct = New Struct Pointer_To_Struct\Value = New_Value Return Handle( Pointer_To_Struct ) End Function ; The above function simply returns an address of a new object of type Struct. ; And the object contains a new value given as parameter when the function was ; first called. The function call would look like this: Address_Of_Pointer% = Create_Struct( 2147483647 ) ; And then you can pass the Address_Of_Pointer variable to another function: Display_Struct( Address_Of_Pointer ) ; That is also how you can utilitize the use of a polymorphic function. Below ; you will find a complete example of a function that handles typeless objects. ; A polymorph is something that has multiple shapes. A C++ 'void' type is ; amorph, meaning not having any shape, or shapeless. ; As a final note, remember that Object and Handle are keywords, so you don't ; *need* to write the parentheses (). It just makes for better reading in most ; cases but in the program below all parentheses are omitted where the Object ; and Handle keywords are used. ;<-- ; Various type definitions Type TInteger Field Value% End Type Type TFloat Field Value# End Type Type TString Field Value$ End Type Type TStringS Field Length% Field Value$ End Type Type Enemies1 Field X% Field Y% Field Hungry% Field Scared% End Type Type Enemies2 ; Exactly the same as Enemies1 to show it works here too Field X% Field Y% Field Hungry% Field Scared% End Type ; Here are 3 different versions of the same polymorphic function Function DisplayEntry1( PointerAddress% ) ; Pre-cast: ; First converting (or attempting to convert), also known as 'casting', the ; PointerAddress to a usable Pointer. Also, this is not true casting, it's ; more like 'cheat'-casting :) Local PointerToInteger.TInteger = Object.TInteger PointerAddress Local PointerToFloat.TFloat = Object.TFloat PointerAddress Local PointerToString.TString = Object.TString PointerAddress Local PointerToStringS.TStringS = Object.TStringS PointerAddress Local PointerToEnemies1.Enemies1 = Object.Enemies1 PointerAddress Local PointerToEnemies2.Enemies2 = Object.Enemies2 PointerAddress ; If conversion/casting failed, a Null pointer is the result. Blitz casting ; is very strict, so you can't accidently cast a similar type record. ; If casting was successful, call another function which displays the ; contents of the object. If PointerToInteger <> Null DisplayValue PointerToInteger\Value ElseIf PointerToFloat <> Null DisplayValue PointerToFloat\Value ElseIf PointerToString <> Null DisplayValue PointerToString\Value ElseIf PointerToStringS <> Null DisplayValue Left( PointerToStringS\Value , PointerToStringS\Length ) ElseIf PointerToEnemies1 <> Null DisplayEnemy1 PointerToEnemies1 ElseIf PointerToEnemies2 <> Null DisplayEnemy2 PointerToEnemies2 End If End Function Function DisplayEntry2( PointerAddress ) ; Cast on-the-fly: ; Check if the address can be casted (and exists) first, then create a ; pointer for usage. If Object.TInteger PointerAddress <> Null PointerToInteger.TInteger = Object.TInteger PointerAddress DisplayValue PointerToInteger\Value ElseIf Object.TFloat PointerAddress <> Null PointerToFloat.TFloat = Object.TFloat PointerAddress DisplayValue PointerToFloat\Value ElseIf Object.TString PointerAddress <> Null PointerToString.TString = Object.TString PointerAddress DisplayValue PointerToString\Value ElseIf Object.TStringS PointerAddress <> Null PointerToStringS.TStringS = Object.TStringS PointerAddress DisplayValue Left( PointerToStringS\Value , PointerToStringS\Length ) ElseIf Object.Enemies1 PointerAddress <> Null PointerToEnemies1.Enemies1 = Object.Enemies1 PointerAddress DisplayEnemy1 PointerToEnemies1 ElseIf Object.Enemies2 PointerAddress <> Null PointerToEnemies2.Enemies2 = Object.Enemies2 PointerAddress DisplayEnemy2 PointerToEnemies2 End If End Function Function DisplayEntry3( PointerAddress ) ; Multi-cast: ; Attempt to cast the PointerAddress to a Pointer. Then cast the valid or ; invalid pointer back to a PointerAddress. An invalid pointer, being Null, ; always casts back to a zero address, so this is actually a redundant cast. If Handle Object.TInteger PointerAddress PointerToInteger.TInteger = Object.TInteger PointerAddress DisplayValue PointerToInteger\Value ElseIf Handle Object.TFloat PointerAddress PointerToFloat.TFloat = Object.TFloat PointerAddress DisplayValue PointerToFloat\Value ElseIf Handle Object.TString PointerAddress PointerToString.TString = Object.TString PointerAddress DisplayValue PointerToString\Value ElseIf Handle Object.TStringS PointerAddress PointerToStringS.TStringS = Object.TStringS PointerAddress DisplayValue Left( PointerToStringS\Value , PointerToStringS\Length ) ElseIf Handle Object.Enemies1 PointerAddress PointerToEnemies1.Enemies1 = Object.Enemies1 PointerAddress DisplayEnemy1 PointerToEnemies1 ElseIf Handle Object.Enemies2 PointerAddress PointerToEnemies2.Enemies2 = Object.Enemies2 PointerAddress DisplayEnemy2 PointerToEnemies2 End If End Function ; Display functions Function DisplayValue( Value$ ) ; This is actually another interesting polymorphic function. Blitz ; automatically casts all native types (integer, float, string) when using a ; string as parameter type. Print Value End Function Function DisplayEnemy1( Enemy.Enemies1 ) ; Demonstration specific for Enemies1. If Enemy\Hungry Color 255 , 255 , 0 ElseIf Enemy\Scared Color 255 , 255 , 255 Else Color 255 , 0 , 0 EndIf Text Enemy\X , Enemy\Y , "X" End Function Function DisplayEnemy2( Enemy.Enemies2 ) ; Demonstration specific for Enemies2. Write "2: " Write Enemy\X + " " Write Enemy\Y + " " Write Enemy\Hungry + " " Print Enemy\Scared End Function ; Back to existentials (implementation). Const ScreenSizeX = 640 Const ScreenSizeY = 480 Graphics ScreenSizeX , ScreenSizeY ; Creating an instance of all basic types. Local PInteger.TInteger = New TInteger PInteger\Value = 2147483647 Local PFloat.TFloat = New TFloat PFloat\Value = 0.2147483647 Local PString.TString = New TString PString\Value = "Hey! That was my line." Local PStringS.TStringS = New TStringS PStringS\Value = "No, it's not. The director altered it." PStringS\Length = 13 ; Then calling the same function to display them all. Note that one needs to ; pass a pointer's address to make it virtually typeless. DisplayEntry1( Handle PInteger ) DisplayEntry1( Handle PFloat ) DisplayEntry1( Handle PString ) DisplayEntry1( Handle PStringS ) ; For demonstrational purposes, 10 random enemies. Const Enemies% = 10 Local Counter% Local PEnemy1.Enemies1 Local PEnemy2.Enemies2 For Counter = 1 To Enemies ; Create an enemy of the first enemy type and fill it with random values. PEnemy1 = New Enemies1 PEnemy1\X = Rnd( ScreenSizeX ) PEnemy1\Y = Rnd( ScreenSizeY ) PEnemy1\Hungry = Rnd( 1 ) PEnemy1\Scared = Rnd( 1 ) ; Create an enemy of the second enemy type, copy values from the first enemy ; and modify it to be completely reversed. PEnemy2 = New Enemies2 PEnemy2\X = ( PEnemy1\X + ScreenSizeX/2 ) Mod ScreenSizeX PEnemy2\Y = ( PEnemy1\Y + ScreenSizeX/2 ) Mod ScreenSizeY PEnemy2\Hungry = Not PEnemy1\Hungry PEnemy2\Scared = Not PEnemy1\Scared DisplayEntry1( Handle( PEnemy1 ) ) DisplayEntry1( Handle( PEnemy2 ) ) Next ; And that's all there is to it :) ;--> ; Have fun :D ;------------------------------------------------------------------------------;
Copyright(c) 2000-2004, BlitzCoder. All Rights Reserved.
Code software created by Krylar's Kreations