Type 中的可变长成员数据
- 来源: https://www.freebasic.net/wiki/wikka.php?wakka=ProPgVariableLengthData
- 最后更新: 2020-07-11
作为 Type 成员的可变长字符串/数组的管理。
前言:
在 FreeBASIC 中,Type 数据结构最终必须是固定大小的,这样编译器才知道为该 Type 的对象分配多少内存。
尽管如此,Type 可以包含可变长字符串或数组数据成员。
但是,字符串/数组的数据不会直接嵌入到 Type 中。相反,Type 只包含字符串/数组描述符结构,FreeBASIC 在幕后使用它来管理可变长字符串/数组数据。
为了确定 Type 中数组描述符结构的大小,可变长数组数据成员必须始终使用 Any(S) 代替数组边界来声明,以便根据指定的 Any 数量固定维度数量。可变长数组数据成员也可以在其声明中使用 ReDim 语法预设大小。
当可变长数组字段在 Type 中声明时,被视为伪对象(可变长字符串是真正的对象)。
因此,Type 的隐式拷贝构造函数和隐式赋值运算符本身支持对此类字符串/数组的[重新]调整大小和复制,或其清空操作。
编译器代码对字符串/数组的隐式调整大小和复制
当编译器为这样的 Type(具有字符串/数组成员)构建默认拷贝构造函数和默认拷贝赋值运算符时,它还包含了所有用于调整目标字符串/数组大小并从源字符串/数组复制数据的代码(如果需要)。
示例:
start GeSHi
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
Sleepend GeSHi
输出:
FreeBASIC
1 2 3 4 5 6 7 8 9
FreeBASIC
1 2 3 4 5 6 7 8 9编译器代码对字符串/数组的隐式调整大小和复制被显式拷贝构造函数和拷贝赋值运算符破坏
如果用户想指定自己的拷贝构造函数和拷贝赋值运算符(例如为了初始化额外的复杂字段成员),则上述编译器代码自动进行的字符串/数组调整大小和复制将被破坏。
示例:
start GeSHi
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
Sleepend GeSHi
输出(空白):
在用户拷贝构造函数和拷贝赋值运算符中显式设置字符串/数组的调整大小和复制
可变长数组不能像可变长字符串那样作为真正的对象处理,因为例如没有隐式赋值。
参照上面的示例,This.array() = u.array() 是不允许的,而 This.s = u.s 是允许的。
用户必须显式编写数组成员的调整大小和复制代码(对于数组数据复制,使用 C 运行时函数 memcpy() 来优化执行时间)。
示例:
start GeSHi
#include "crt/string.bi" '' 'memcpy()' 的 C 运行时头文件
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 '' 显式数组大小调整和复制
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 '' 非自我赋值
This.s = u.s
If UBound(u.array) >= LBound(u.array) Then '' 显式数组大小调整和复制
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
Sleepend GeSHi
输出:
FreeBASIC
1 2 3 4 5 6 7 8 9
FreeBASIC
1 2 3 4 5 6 7 8 9使用包含可变长字符串和数组的额外基类 Type
另一种优雅的可能性是保留编译器自动编码的调整大小/复制功能,但只需显式调用它。
为此,对于成员数组,一个优雅的解决方案是不再将其放在 Type 本身的级别,而是放在另一个特定的继承 Type 中(从外部看完全相同)。对于成员字符串,这不是必要的,但一并包含可以每次节省一行代码。
示例:
start GeSHi
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) '' 继承基类隐式拷贝构造函数调用,实现字符串复制及数组大小调整和复制
'code for user fields in copy-constructor(此处为拷贝构造函数中用户字段的代码)
End Constructor
Operator UDT.Let (ByRef u As UDT)
Cast(UDT0, This) = u '' 继承基类隐式拷贝赋值运算符调用,实现字符串复制及数组大小调整和复制
'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
Sleepend GeSHi
输出:
FreeBASIC
1 2 3 4 5 6 7 8 9
FreeBASIC
1 2 3 4 5 6 7 8 9参见
返回 目录