Имитация полиморфизма
 
Автор rdc

Введение


Полиморфизм в объектно-ориентированном программировании является мощным инструментом. Полиморфные метод (Sub или Function) ведут себя по-разному в зависимости от определения объекта. Например объект животного может иметь метод speak, который будет выдавать лай для собаки и мяуканье для кошки. FreeBasic пока не поддерживает истинный полиморфизм; Это будет добавлено, когда классы будут реализованы. Однако вы можете смоделировать полиморфные методы, с использованием метода указателей.

Полиморфизм


Полиморфные методы являются подпрограммами или функциями, которые имеют тот же тип и список параметров, но ведут себя по-разному при привязке к разным объектам.

В следующем листинге показаны 2 определения и расширенный тип:
#define isdog 1
#define iscat 2

Type animal
    Public:
    speak As Sub()
    Declare Constructor (anid As Integer)    
End Type

#defines передается в конструктор, чтобы сигнализировать, какой тип объекта создается. speak As Sub() определяет указатель метода. Как вы увидите, адрес двух различных подпрограмм будет передан по указателю в метод speak. Следующий листинг показывает, что speak получает разные адреса в конструкторе:
'Speak метод для объекта dog(собаки)
Sub Bark()
    Print "Woof!"
End Sub

'Speak метод для объекта cat(кошки)
Sub Meow()
    Print "Meow!"
End Sub

'Установим указатель правильного метода, основанный на id животного
Constructor animal(anid As Integer)
    If anid = isdog Then
        this.speak = @Bark
    ElseIf anid = iscat Then
        this.speak = @Meow
    End If
End Constructor

Подпрограмма Bark будет вызываться, если объект является dog , а подпрограмма Meow будет вызываться, если объект является cat. Вы можете быть удивлены, почему нельзя просто перегрузить метод? Для перегруженных методов тип и список параметров должны быть уникальными, а в полиморфных методах тип и список параметров должны быть одинаковыми. Поскольку Bark and Meow имеют такой же список параметров, т.е. без параметров, невозможно перегрузить метод.

Код конструктора определяет, какой метод использовать. Если anid равно isdog, то указатель метода Speak установится на адрес подпрограммы Bark. Если anid равно iscat , то будет присвоен адрес Meow. Оператор @ (адрес из) используется для передачи адреса Bark и Meow методу Speak.

Объектная ссылка this - это скрытый параметр, который передается в конструктор, который ссылается на тип, в данном случае animal. Вы можете использовать this для ссылки на внутренние переменные внутри типа

Единственное, что осталось сделать, это создать и инициализировать объекты:
'Создание объектов dog и cat
Dim myDog As animal = isdog
Dim mycat As animal = iscat

Здесь myDog и myCat создаются с соответствующими флагами, передаваемыми конструктору. После создания объекта можно вызвать метод speak для каждого объекта.
'Вывод того, что произносят животные
Print "My dog says ";
myDog.speak()
Print "My cat says ";
myCat.speak()

Обратите внимание, что вызывается один и тот же метод, но вывод отличается:
My dog says Woof!
My cat says Meow!

Это суть полиморфных методов.

Вот полный листинг:
'Имитация полиморфизма с помощью метода указателей
'Richard D. Clark
'Требуется версия CVS FreeBasic
'**********************************************

#define isdog 1
#define iscat 2


Type animal
    Public:
    speak As Sub()
    Declare Constructor (anid As Integer)    
End Type

'Speak метод для объекта dog(собаки)
Sub Bark()
    Print "Woof!"
End Sub

'Speak метод для объекта cat(кошки)
Sub Meow()
    Print "Meow!"
End Sub

'Установим указатель правильного метода, основанный на id животного
Constructor animal(anid As Integer)
    If anid = isdog Then
        this.speak = @Bark
    ElseIf anid = iscat Then
        this.speak = @Meow
    End If
End Constructor

'Создание объектов dog и cat
Dim myDog As animal = isdog
Dim mycat As animal = iscat

'Вывод того, что произносят животные
Print "My dog says ";
myDog.speak()
Print "My cat says ";
myCat.speak()

Sleep
End