Simulating Polymorphism
Written by rdc
Introduction
Polymorphism is a powerful tool in object-oriented program. A polymorphic method (Sub or Function) behaves differently depending on the definition of the object. For example, an animal object may have a speak method that will issue a bark for a dog and a meow for a cat. FreeBasic doesn't support true polymorphism before version 0.90.0. However, you can simulate polymorphic methods using method pointers.
Polymorphism
Polymorphic methods are subroutines or functions that have the same type and parameter list, but behave differently when bound to different objects. An animal object may have a Speak method that will issue a bark for a dog and a meow for a cat. Since FreeBasic doesn't yet have classes, you cannot implement true polymorphic methods, but you can simulate the behavior by using method pointers.
The following listing shows a couple of defines and an extended type declaration:
`
#define isdog 1
#define iscat 2
Type animal
Public:
speak As Sub()
Declare Constructor (anid As Integer)
End Type
`
The #defines are passed to the Constructor to signal what type of object is being created. The speak As Sub() definition defines the method pointer. As you will see, the address of two different subroutines will be passed to the speak method pointer. The following listing shows the different speak subroutines and the Constructor method:
`
'Speak method for dog object
Sub Bark()
Print "Woof!"
End Sub
'Speak method for cat object
Sub Meow()
Print "Meow!"
End Sub
'Set the proper method pointer based on animal id
Constructor animal(anid As Integer)
If anid = isdog Then
this.speak = @Bark
ElseIf anid = iscat Then
this.speak = @Meow
End If
End Constructor
`
The Bark subroutine will be called if the object is a dog and the Meow subroutine will be called if the object is a cat. You may be wondering why you can't just overload the method? For overloaded methods, the type and parameter list must be unique, where in a polymorphic method, the type and parameter list must be the same. Since Bark and Meow have the same parameter list, that is no parameters, you cannot overload the method.
The Constructor code is where the program decides what method call to use. If anid is equal to isdog, then the Speak method pointer will be set to the address of the Bark subroutine. If anid is equal to iscat then Speak will be set to the address of the Meow subroutine. The addressof operator @ is used to pass the address of Bark and Meow to the Speak pointer.
The this object reference is a hidden parameter that is passed to the Constructor that references the type, which in this case is animal. You can use this to reference the internal variables within the type.
The only thing left to do is to create and initialize the object:
`
'Create a dog and cat object
Dim myDog As animal = isdog
Dim mycat As animal = iscat
`
Here myDog and myCat are created with the appropriate flags passed to the Constructor so that the proper references can be set up. Once the object are created you can call the speak method of each object.
`
'Have the animals speak
Print "My dog says ";
myDog.speak()
Print "My cat says ";
myCat.speak()
`
Notice that you are calling the same speak method, yet the output is different:
`
My dog says Woof!
My cat says Meow!
`
This is the essence of polymorphic methods.
Here is the complete program listing:
`
'Simulated Polymorphism Using Method Pointers
'Richard D. Clark
'Requires the CVS version of FreeBasic
'**********************************************
#define isdog 1
#define iscat 2
Type animal
Public:
speak As Sub()
Declare Constructor (anid As Integer)
End Type
'Speak method for dog object
Sub Bark()
Print "Woof!"
End Sub
'Speak mehod for cat object
Sub Meow()
Print "Meow!"
End Sub
'Set the proper method pointer based on animal id
Constructor animal(anid As Integer)
If anid = isdog Then
this.speak = @Bark
ElseIf anid = iscat Then
this.speak = @Meow
End If
End Constructor
'Create a dog and cat object
Dim myDog As animal = isdog
Dim mycat As animal = iscat
'Have the animals speak
Print "My dog says ";
myDog.speak()
Print "My cat says ";
myCat.speak()
Sleep
End
`
From fbc version 0.90.0, polymorphism through inheritance and virtuality is supported
Previous example transposed for fbc version 0.90.0 or greater, by using polymorphism through inheritance with abstract/virtual methods (feature now supported):
`
'Requires FreeBasic version >= 0.90.0
'Base-type animal
Type animal Extends Object
Declare Abstract Sub speak ()
End Type
'Derived-type dog
Type dog Extends animal
Declare Virtual Sub speak () Override
End Type
'Speak method for dog object
Virtual Sub dog.speak ()
Print "Woof!"
End Sub
'Derived-type cat
Type cat Extends animal
Declare Virtual Sub speak () Override
End Type
'Speak mehod for cat object
Virtual Sub cat.speak ()
Print "Meow!"
End Sub
'Create a dog and cat as dynamic object through animal pointer
Dim myDog As animal Ptr = New dog
Dim mycat As animal Ptr = New cat
'Have the animals speak
Print "My dog says ";
myDog->speak()
Print "My cat says ";
myCat->speak()
Sleep
'Delete the dynamic objects
Delete myDog
Delete myCat
`