Указатели на процедуры
 
Указатели, которые указывают на процедуры

Так же, как указатели можно сделать для типов Integer или Single, можно сделать их и для процедур, то есть, они могут хранить адрес процедуры.

Декларация

Чтобы объявить указатель на процедуру, нужно использовать ключевые слова Sub или Function, а затем уже любые параметры и тип возвращаемого значения:

' объявляет указатель на процедуру, которая не принимает аргументов
Dim pointerToProcedure As Sub

Указатель на процедуру хранит адрес процедуры, который извлекается с помощью оператора @ (адрес из) или Procptr оператора:

Function Add (a As Integer, b As Integer) As Integer
    Return a + b
End Function

Dim pFunc As Function (As Integer, As Integer) As Integer = @Add


Вызов процедуры указателя

Интересной особенностью процедуры указателя является то, что они могут вызываться как обычная процедура:

'' .. Сложение с помощью pFunc ..
#include once "pfunc.bi"

Print "3 + 4 = " & pFunc(3, 4)


Передача указателей на процедуры в процедуру

Передача указателей на процедуры в другие процедуры также просто:

'' .. Сложение с помощью pFunc ..
#include once "pfunc.bi"

Function DoOperation (a As Integer, b As Integer, operation As Function (As Integer, As Integer) As Integer) As Integer
    Return operation(a, b)
End Function

Print "3 + 4 = " & DoOperation(3, 4, @Add)

Поскольку декларации указателя процедуры могут быть длинными, можно создать псевдоним типа для указателя процедуры, чтобы сделать более удобный код:

'' .. Сложение с помощью pFunc ..
#include once "pfunc.bi"

Type operation As Function (As Integer, As Integer) As Integer

Function DoOperation (a As Integer, b As Integer, op As operation) As Integer
    Return op(a, b)
End Function

Print "3 + 4 = " & DoOperation(3, 4, @Add)


Указатели на процедурные указатели

Поскольку синтаксис указателя процедуры не позволяет сделать декларацию указателя на указатель процедуры, то для этого псевдоним типа используется. Обратите внимание, как надо окружать в скобках разыменованный указатель на указатель процедуры. Это потому, что оператор вызова функции '()' имеет более высокий приоритет, чем оператор * (значение из):

Sub Halve (ByRef i As Integer)
    i /= 2
End Sub

Sub Triple (ByRef i As Integer)
    i *= 3
End Sub

Type operation As Sub (ByRef As Integer)

' массив процедурных указателей, NULL указывает
' на конец массива
Dim operations(20) As operation = _
{ @Halve, @Triple, 0 }

Dim i As Integer = 280

' применить все operations в переменную, путем использования итератора
' для массива с указателями на указатели процедуры

Dim op As operation Ptr = @operations(0)
While (0 <> *op)
    ' вызываем процедуры по порядку, обратите внимание на дополнительные скобки
    (*op)(i)
    op += 1
Wend

Print "Value of 'i' after all operations performed: " & i


Указатели на процедуры-элементы

Метод указателей еще не реализован, но это можно обойти, используя статический враппер:

/'
' В этом примере показано, как можно имитировать получения указателя на метод класса,
' до тех пор, пока поддержка не будет реализована должным образом в компиляторе.
'
' Когда это будет поддерживаться, вам только нужно будет удалить статический враппер
' функции, представленный здесь, чтобы сохранить совместимость.

 '/

Type T
    Declare Function test(ByVal number As Integer) As Integer
    Declare Static Function test(ByRef This As T, ByVal number As Integer) As Integer
    Dim As Integer i = 420
End Type

Function T.test(ByVal number As Integer) As Integer
    Return i + number
End Function

Function T.test(ByRef This As T, ByVal number As Integer) As Integer
    Return this.test(number)
End Function

Dim p As Function(ByRef As T, ByVal As Integer) As Integer
p = @T.test

Dim As T obj

Print p(obj, 69) '' печатает 489


См. также