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

FreeBASIC ProPgVariableLengthData

目次→教本→プログラマーのための案内Variable-length member data←オリジナル・サイト

可変長メンバー・データ 左にメニュー・フレームが表示されていない場合は、ここをクリックして下さい

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

可変長の文字列/配列 を型のメンバーとして管理する。

序文:
FreeBASIC では、型データ構造は最終的に固定サイズでなければならず、コンパイラはその型のオブジェクトに割り当てるメモリ量を知ることができます。
しかし、型には可変長の文字列や配列のデータメンバを含めることができます。

しかし、文字列/配列のデータは直接型には埋め込まれません。代わりに、型には文字列/配列記述子構造だけが含まれ、FreeBASIC は裏でこれを使って可変長の文字列/配列データを管理します。
型の配列記述子の構造をサイズ調整するために、可変長の配列データメンバーは、配列境界の代わりに常に Any を使って宣言する必要があります。指定された Any の数に基づいて次元数を固定します。可変長の配列データメンバーは、ReDim を含む構文を使って、宣言時にあらかじめサイズを指定することもできます。

可変長配列フィールドは、型で宣言されたときに、擬似オブジェクトとみなされます(可変長の文字列は実オブジェクトです)。
そのため、型自体の暗黙のコピー構築子と暗黙の let 演算子が、このような文字列/配列の[再]サイジングとコピー、またそれらの消去をサポートしています。

コンパイラ・コードによる暗黙の文字列/配列のサイジングとコピー
コンパイラがこのような型(文字列/配列のメンバを持つ)のためにデフォルトのコピー構築子とデフォルトのコピー割り当て演算子を構築するとき、必要に応じて、送信先の文字列/配列のサイズ調整と送信元の文字列/配列からのデータのコピーのためのすべてのコードが含まれます。

例:
Type UDT
    Dim As String s
    Dim As Integer array(Any)
End Type

Dim As UDT u1, u2

u1.s = "FreeBASIC"
ReDim u1.array(1 To 9)
For I As Integer = LBound(u1.array) To UBound(u1.array)
    u1.array(I) = I
Next I
 
u2 = u1
Print u2.s
For I As Integer = LBound(u2.array) To UBound(u2.array)
    Print u2.array(I);
Next I
Print
Print

Dim As UDT u3 = u1
Print u3.s
For I As Integer = LBound(u3.array) To UBound(u3.array)
    Print u3.array(I);
Next I
Print

Sleep


出力:
FreeBASIC
 1 2 3 4 5 6 7 8 9

FreeBASIC
 1 2 3 4 5 6 7 8 9

コンパイラコードによる暗黙の文字列/配列のサイズ調整とコピーが、明示的なコピー構築子とコピー代入演算子によって破壊される
ユーザーが独自のコピー構築子とコピー代入演算子を指定する場合(例えば、追加の複雑な項目メンバを初期化するため)、上記のコンパイラ・コードによる自動的な文字列/配列のサイズ調整とコピーは解除されます。

例:
Type UDT
    Dim As String s
    Dim As Integer array(Any)
    Declare Constructor ()
    Declare Constructor (ByRef u As UDT)
    Declare Operator Let (ByRef u As UDT)
    'user fields
End Type

Constructor UDT ()
    'code for user fields in constructor
End Constructor

Constructor UDT (ByRef u As UDT)
    'code for user fields in copy-constructor
End Constructor

Operator UDT.Let (ByRef u As UDT)
    'code for user fields in copy-assignement operator
End Operator

Dim As UDT u1, u2

u1.s = "FreeBASIC"
ReDim u1.array(1 To 9)
For I As Integer = LBound(u1.array) To UBound(u1.array)
    u1.array(I) = I
Next I
 
u2 = u1
Print u2.s
For I As Integer = LBound(u2.array) To UBound(u2.array)
    Print u2.array(I);
Next I
Print
Print

Dim As UDT u3 = u1
Print u3.s
For I As Integer = LBound(u3.array) To UBound(u3.array)
    Print u3.array(I);
Next I
Print

Sleep

出力 (空白):
			

文字列/配列のサイズ調整とコピーは、ユーザーのコピー構築子とコピー代入演算子で明示的に設定される
可変長配列は、例えば暗黙の代入がないため、可変長文字列のように真のオブジェクトとして処理することはできません。
上記の例で言えば、This.array() = u.array() は許可されませんが、This.s = u.s は許可されます。
ユーザーは、配列メンバのサイズ設定とコピーを明示的にコーディングする必要があります(配列データのコピーには、実行時間を最適化するために、C言語のランタイム関数 memcpy() が使われます)。

例:
#include "crt/string.bi"  '' C run-time header for 'memcpy()'

Type UDT
    Dim As String s
    Dim As Integer array(Any)
    Declare Constructor ()
    Declare Constructor (ByRef u As UDT)
    Declare Operator Let (ByRef u As UDT)
    'user fields
End Type

Constructor UDT ()
    'code for user fields in constructor
End Constructor

Constructor UDT (ByRef u As UDT)
    This.s = u.s
    If UBound(u.array) >= LBound(u.array) Then  '' explicit array sizing and copying
        ReDim This.array(LBound(u.array) To UBound(u.array))
        memcpy(@This.array(LBound(This.array)), @u.array(LBound(u.array)), (UBound(u.array) - LBound(u.array) + 1) * SizeOf(@u.array(LBound(u.array))))
    End If
    'code for user fields in copy-constructor
End Constructor

Operator UDT.Let (ByRef u As UDT)
    If @This <> @u Then  '' not self-assignment
        This.s = u.s
        If UBound(u.array) >= LBound(u.array) Then  '' explicit array sizing and copying
            ReDim This.array(LBound(u.array) To UBound(u.array))
            memcpy(@This.array(LBound(This.array)), @u.array(LBound(u.array)), (UBound(u.array) - LBound(u.array) + 1) * SizeOf(@u.array(LBound(u.array))))
        End If
        'code for user fields in copy-assignement operator
    End If
End Operator

Dim As UDT u1, u2

u1.s = "FreeBASIC"
ReDim u1.array(1 To 9)
For I As Integer = LBound(u1.array) To UBound(u1.array)
    u1.array(I) = I
Next I
 
u2 = u1
Print u2.s
For I As Integer = LBound(u2.array) To UBound(u2.array)
    Print u2.array(I);
Next I
Print
Print

Dim As UDT u3 = u1
Print u3.s
For I As Integer = LBound(u3.array) To UBound(u3.array)
    Print u3.array(I);
Next I
Print

Sleep

出力:
FreeBASIC
 1 2 3 4 5 6 7 8 9

FreeBASIC
 1 2 3 4 5 6 7 8 9

可変長の文字列と配列を含む追加のベース型を使う
もう 1つの洗練された方法は、コンパイラによって自動的にコーディングされたこのサイズ変更やコピーを、単に明示的に呼び出すことです。
この場合、メンバー配列の洗練された解決策は、もはや型自体のレベルに置くのではなく、継承された別の特定の型に配置することです(外から見ると、まったく同じです)。これはメンバー文字列には必要ありませんが、これを含めることで、毎回コードを 1行減らすことができます。

例:
Type UDT0
    Dim As String s
    Dim As Integer array(Any)
End Type

Type UDT Extends UDT0
    Declare Constructor ()
    Declare Constructor (ByRef u As UDT)
    Declare Operator Let (ByRef u As UDT)
    'user fields
End Type

Constructor UDT ()
    'code for user fields in constructor
End Constructor

Constructor UDT (ByRef u As UDT)
    Base(u)  '' inherited string copying plus array sizing and copying from Base implicit copy-constructor call
    'code for user fields in copy-constructor
End Constructor

Operator UDT.Let (ByRef u As UDT)
    Cast(UDT0, This) = u  '' inherited string copying plus array sizing and copying from Base implicit copy-assignement operator call
    'code for user fields in copy-assignement operator
End Operator

Dim As UDT u1, u2

u1.s = "FreeBASIC"
ReDim u1.array(1 To 9)
For I As Integer = LBound(u1.array) To UBound(u1.array)
    u1.array(I) = I
Next I
 
u2 = u1
Print u2.s
For I As Integer = LBound(u2.array) To UBound(u2.array)
    Print u2.array(I);
Next I
Print
Print

Dim As UDT u3 = u1
Print u3.s
For I As Integer = LBound(u3.array) To UBound(u3.array)
    Print u3.array(I);
Next I
Print

Sleep


出力:
FreeBASIC
 1 2 3 4 5 6 7 8 9

FreeBASIC
 1 2 3 4 5 6 7 8 9

参照:
プログラマーのための案内に戻る
目次に戻る
←リンク元に戻る プログラム開発関連に戻る

ページ歴史:2020-07-11 00:59:08
日本語翻訳:WATANABE Makoto、原文著作者:fxm

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

表示-非営利-継承