手続きを示すポインタ
ポインターが、
Integer や
Single 型を示すことができるように、ポインターは手続きを示すことができます。つまり、ポインターは手続きのアドレスを格納することができます。
宣言
' 引数を取らない sub 手続きに、ポインタを宣言します
Dim pointerToProcedure As Sub
'' pfunc.bi
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.bi という名前で保存して下さい。
手続きポインタを、呼び出す
手続きポインタが興味深い点は、まさしく手続きのように、ポインタを呼ぶことができることです:
'' .. 加算に、上で宣言した pFunc を使います ..
#include once "pfunc.bi"
Print "3 + 4 = " & pFunc(3, 4)
Sleep
渡辺 注:このプログラムは、上で保存した pfunc.bi と同じフォルダから、コンパイルして実行して下さい。
サブルーチン・ポインタの呼び出しの例については、
Operator @ (Address of) のページを参照下さい。
注: 手続き・ポインターを通して手続きを呼び出すときには、ポインター値への単純なアクセスであいまいさを解決するために、引数リストを囲む括弧(空の場合でも)が必須です。
手続きポインタを、手続きに渡す
手続きポインタを他の手続きに渡すのも、また同様です:
'' .. 前の通り、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)
Sleep
手続きポインタ宣言が長くなる場合があるので、手続きポインタのために型の別名を作成する場合が、多々有ります。タイプ別名を使うと、コードが分かり易くなることがあるからです:
'' .. 前の通り、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)
Sleep
手続きポインタへのポインタ
手続きポインタの構文が、手続きが関数の場合、手続きポインタへのポインタの宣言を許容しないので、タイプ別名が使われます。
(関数だと、ptr は、手続きではなく戻り型に当てはまるからです。)
手続きを呼ぶときには、手続きポインターに間接参照されたポインターを、括弧で囲む必要がある点に、注意して下さい。
これは、関数呼び出し演算子 '()' が、
演算子 * (Value of) より優先順位が高いからです:
Function Halve (ByVal i As Integer) As Integer
Return i / 2
End Function
Function Triple (ByVal i As Integer) As Integer
Return i * 3
End Function
Type operation As Function (ByVal As Integer) As Integer
' 手続きポインタの配列、
' NULL は、配列の端を示します
Dim operations(20) As operation = _
{ @Halve, @Triple, 0 }
Dim i As Integer = 280
' 配列を通して、手続きポインターへのポインターを繰り返すことによって、
' 操作のすべてを、変数に適用します。
Dim op As operation Ptr = @operations(0)
While (*op <> 0)
' 指定される手続きを呼びます。余分な括弧に注意してください
i = (*op)(i)
op += 1
Wend
Print "すべての操作を実施した後の'i'の値は: & i
Sleep
メンバー手続きへのポインター
メソッド・ポインターは、まだ実装されていません。しかし、これは、静的なラッパーを使うことで対処できます。
/''
' この例は、サポートがコンパイラーの中で適切に実装されるまで、
' クラス・メソッド・ポインターを得ることをシミュレートする方法を示します。
'
' これがサポートされたら、互換性を維持するために、
' ここで示された静的なラッパー関数を削除するだけです。
'/
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) '' prints 489
Sleep
fbc 1.10.0 以降、メソッドポインタは 'Procptr' 演算子を更新することで実装されている:
/''
' This example shows, since fbc 1.10.0, how to directly obtain a class method pointer,
'/
Type T
Declare Function test(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
Dim p As Function(ByRef As T, ByVal As Integer) As Integer
p = ProcPtr(T.test) '' or 'p = @T.test'
Dim As T obj
Print p(obj, 69) '' prints 489
反変パラメータと共変結果を持つ関数を、関数ポインタに代入します。両方ともポインタによって行われます:
'Example of assigning to a function pointer a function with:
' - a contravariant parameter by pointer,
' - and a covariant result by pointer.
Type A
Dim As Integer I
Declare Constructor ()
Declare Destructor ()
End Type
Constructor A ()
Print " A instance constructed", @This
End Constructor
Destructor A ()
Print " A instance destroyed", @This
End Destructor
Type B Extends A
Dim As Integer J
Declare Constructor ()
Declare Constructor (ByRef a0 As A)
Declare Destructor ()
End Type
Constructor B ()
Print " B instance constructed", @This
End Constructor
Constructor B (ByRef a0 As A)
Cast(A, This) = a0
Print " B instance constructed", @This
End Constructor
Destructor B ()
Print " B instance destroyed", @This
End Destructor
Function f (ByVal pa0 As A Ptr) As B Ptr
Return New B(*pa0)
End Function
Scope
Dim As Function (ByVal As B Ptr) As A Ptr pf = @f
Print "'Scope : Dim As B b0':"
Dim As B b0
Print
Print "'Dim As A Ptr pab = pf(@b0)':"
Dim As A Ptr pab = pf(@b0)
Print
Print "'Delete CPtr(B Ptr, pab)':"
Delete CPtr(B Ptr, pab)
Print
Print "'End Scope':"
End Scope
Sleep
両方とも参照により、反変パラメーターと共変結果を持つ関数を、関数ポインターに代入します:
'Example of assigning to a function pointer a function with:
' - a contravariant parameter by reference,
' - and a covariant result by reference.
Type A Extends Object
Dim As Integer I
Declare Constructor ()
Declare Virtual Destructor ()
End Type
Constructor A ()
Print " A instance constructed", @This
End Constructor
Destructor A ()
Print " A instance destroyed", @This
End Destructor
Type B Extends A
Dim As Integer J
Declare Constructor ()
Declare Constructor (ByRef a0 As A)
Declare Virtual Destructor ()
End Type
Constructor B ()
Print " B instance constructed", @This
End Constructor
Constructor B (ByRef a0 As A)
Cast(A, This) = a0
Print " B instance constructed", @This
End Constructor
Destructor B ()
Print " B instance destroyed", @This
End Destructor
Function f (ByRef a0 As A) ByRef As B
Return *New B(a0)
End Function
Scope
Dim As Function (ByRef As B) ByRef As A pf = @f
Print "'Scope : Dim As B b0':"
Dim As B b0
Print
Print "'Dim Byref As A rab = pf(b0)':"
Dim ByRef As A rab = pf(b0)
Print
Print "'Delete @rab':"
Delete @rab
Print
Print "'End Scope':"
End Scope
Sleep
旧プログラム例
'Example of assigning to a function pointer a function with a contravariant parameter and a covariant result.
'反変引数と共変結果を持つ関数を、関数ポインタに代入する例
Type A
Dim As Integer I
End Type
Type B Extends A
Dim As Integer J
End Type
Function f (ByRef a0 As A) As B Ptr
Print "B のインスタンスが作成されました"
Return New B(a0)
End Function
Dim As Function (ByRef As B) As A Ptr pf = @f
Dim As B b0
Dim As A Ptr pab = pf(b0)
Sleep
Delete CPtr(B Ptr, pab)
参照: