FreeBASIC マニュアルのトップに戻る

FreeBASIC ProPgProcedurePointers

目次→教本→プログラマーのための案内Pointers to Procedures←オリジナル・サイト

手続きへのポインタ 左にメニュー・フレームが表示されていない場合は、ここをクリックして下さい

←リンク元に戻る プログラム開発関連に戻る

手続きを示すポインタ

ポインターが、IntegerSingle 型を示すことができるように、ポインターは手続きを示すことができます。つまり、ポインターは手続きのアドレスを格納することができます。

宣言
手続きへのポインターを宣言するために、SubFunction を使います。SubFunction の後ろには、任意のパラメーターと、戻り値型が続きます。

' 引数を取らない sub 手続きに、ポインタを宣言します
Dim pointerToProcedure As Sub


手続きポインターは、手続きアドレスを格納します。手続きアドレスは、演算子 @ (のアドレス)、あるいは ProcPtr operator を使って検索されます。

'' 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)


参照:
プログラマーのための案内に戻る
←リンク元に戻る プログラム開発関連に戻る
ページ歴史:2024-02-15 11:02:47
日本語翻訳:WATANABE Makoto、原文著作者:LaananFisher

ホームページのトップに戻る

表示-非営利-継承