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 did not support true 
polymorphism before. However, you could 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

 Polymorphism through inheritance and virtuality is now supported 

Previous example now transposed, by using polymorphism through inheritance 
with abstract/virtual methods (feature now supported):
   '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

