^符号有两个用途,在我们的例子中都用到了。当它出现在一个类型标志符前面时:
^typeName
它表示一个指向typeName 类型的变量的指针;当它出现在一个指针变量的后面时:
pointer^
它表示对指针解除引用,换句话说,它返回在指针所指向的地址处保存的值。
除了使用@运算符,你也可以使用几个标准例程给一个指针赋值。New 和GetMem 过程把一个内存地址
赋给指针,而Addr 和Ptr 函数则返回一个指向特定变量或地址的指针。
保留字nil 是一个特殊常量,可赋给任何指针(类型)。当nil 被赋给一个指针时,指针不表示任何东西。
使用下面的语法,你能声明一个任意类型的指针,
type pointerTypeName = ^type
当定义一个记录类型(或其它数据类型)时,习惯上也就定义了一个此类型的指针,这使得处理更容易,
我们不需要拷贝一大块内存。
在Pointer 类型变量的后面使用^运算符会引发编译错误。要访问一个Pointer 类型引用的变量,首先把它
转换为其它指针类型,然后再解除引用。
基本(fundamental)类型PAnsiChar 和PWideChar 分别表示AnsiChar 和WideChar 值的指针,一般(generic)
类型PChar 表示一个指向Char 的指针(在当前实现中,它表示AnsiChar)。这些字符指针用来操纵零结
尾字符串
System 和SysUtils 单元定义了许多常用的标准指针类型:
Pointer type Points to variables of type
PAnsiString,PString AnsiString
PByteArray TByteArray (declared in SysUtils).
Used to typecast dynamically allocated memory for array access.
PCurrency,PDouble,
PExtended,PSingle Currency,Double,Extended,Single
PInteger Integer POleVariant OleVariant
PShortString ShortString. Useful when porting legacy code that uses the old PString type.
PTextBuf TTextBuf (declared in SysUtils).
TTextBuf is the internal buffer type in a TTextRec file record.)
PVarRec TVarRec (declared in System)
PVariant Variant
PWideString WideString
PWordArray TWordArray (declared in SysUtils).
Used to typecast dynamically allocated memory for arrays of 2-byte values.
过程类型允许你把过程和函数作为“值”看待,它可以赋给变量或传给其它过程和函数。比如,假设你
定义了一个叫做Calc 的函数,它有两个整型参数并返回一个整数值:
function Calc(X,Y: Integer): Integer;
你可以把Calc 函数赋给变量F:
var F: function(X,Y: Integer): Integer;
F := Calc;
我们只取过程或函数头(heading)并把procedure 或function 后面的标志符去掉,剩下的就是过程类型
的名称。
可以在声明变量时直接使用这样的名称(就像上面的例子一样),也可以声明新类型:
type
TIntegerFunction = function: Integer;
TProcedure = procedure;
TStrProc = procedure(const S: string);
TMathFunc = function(X: Double): Double;
var
F: TIntegerFunction; {F 是一个无参数、返回整数值的函数}
Proc: TProcedure; { Proc 是一个无参数过程}
SP: TStrProc; { SP 是一个使用string 类型参数的过程}
M: TMathFunc; { M 是一个使用Double 类型参数、返回Double 值的函数}
procedure FuncProc(P: TIntegerFunction); { FuncProc 是一个过程,它的参数是一个无参数、返回整数值的函数}
上面的所有变量都是过程指针,也就是指向过程或函数地址的指针。若想引用一个实例对象的方法(参
考Classes and objects),你需要在过程类型的名称后面加上of object。比如
type
TMethod = procedure of object;
TNotifyEvent = procedure(Sender: TObject) of object;
这些类型表示方法指针。方法指针实际上是一对指针:第一个存储方法的地址,第二个存储方法所属的
对象的引用。给出下面的声明
type
TNotifyEvent = procedure(Sender: TObject) of object;
TMainForm = class(TForm)
procedure ButtonClick(Sender: TObject);
...
end;
var
MainForm: TMainForm;
onClick: TNotifyEvent
我们就可以进行下面的赋值:
onClick := MainForm.ButtonClick;
两个过程类型是兼容的,如果它们具有
􀁺 相同的调用约定,
􀁺 相同类型的返回值(或没有返回值),并且具有
􀁺 相同数目的参数,并且相应位置上的类型也相同(参数名无关紧要)
过程指针和方法指针是不兼容的。nil 可以赋给任何过程类型。
嵌套的过程和函数(在其它例程中声明的例程)不能被用作过程类型值,内置的过程和函数也不可以。
若想使用内置的过程作为过程类型值,比如Length,你可以给它加一个包装:
function FLength(S: string): Integer;
begin
Result := Length(S);
end;
。要比较F 和MyFunction 的过程值,使用
if @F = @MyFunction then ...;
@F 把F 转换为无类型指针变量,它包含的是地址,@MyFunction 返回的是MyFunction 的地址。
要取得过程变量的内存地址(而不是它包含的地址),使用@@。比如,@@F 返回F 的地址。
@运算符也可以用来把一个无类型指针值赋给过程变量,比如
var StrComp: function(Str1, Str2: PChar): Integer;
...
@StrComp := GetProcAddress(KernelHandle, ’lstrcmpi’);
调用GetProcAddress 函数,并使StrComp 指向结果。
要测试一个过程变量是否被赋值,使用标准函数Assigned:
if Assigned(onClick) then onClick(X);
^typeName
它表示一个指向typeName 类型的变量的指针;当它出现在一个指针变量的后面时:
pointer^
它表示对指针解除引用,换句话说,它返回在指针所指向的地址处保存的值。
除了使用@运算符,你也可以使用几个标准例程给一个指针赋值。New 和GetMem 过程把一个内存地址
赋给指针,而Addr 和Ptr 函数则返回一个指向特定变量或地址的指针。
保留字nil 是一个特殊常量,可赋给任何指针(类型)。当nil 被赋给一个指针时,指针不表示任何东西。
使用下面的语法,你能声明一个任意类型的指针,
type pointerTypeName = ^type
当定义一个记录类型(或其它数据类型)时,习惯上也就定义了一个此类型的指针,这使得处理更容易,
我们不需要拷贝一大块内存。
在Pointer 类型变量的后面使用^运算符会引发编译错误。要访问一个Pointer 类型引用的变量,首先把它
转换为其它指针类型,然后再解除引用。
基本(fundamental)类型PAnsiChar 和PWideChar 分别表示AnsiChar 和WideChar 值的指针,一般(generic)
类型PChar 表示一个指向Char 的指针(在当前实现中,它表示AnsiChar)。这些字符指针用来操纵零结
尾字符串
System 和SysUtils 单元定义了许多常用的标准指针类型:
Pointer type Points to variables of type
PAnsiString,PString AnsiString
PByteArray TByteArray (declared in SysUtils).
Used to typecast dynamically allocated memory for array access.
PCurrency,PDouble,
PExtended,PSingle Currency,Double,Extended,Single
PInteger Integer POleVariant OleVariant
PShortString ShortString. Useful when porting legacy code that uses the old PString type.
PTextBuf TTextBuf (declared in SysUtils).
TTextBuf is the internal buffer type in a TTextRec file record.)
PVarRec TVarRec (declared in System)
PVariant Variant
PWideString WideString
PWordArray TWordArray (declared in SysUtils).
Used to typecast dynamically allocated memory for arrays of 2-byte values.
过程类型允许你把过程和函数作为“值”看待,它可以赋给变量或传给其它过程和函数。比如,假设你
定义了一个叫做Calc 的函数,它有两个整型参数并返回一个整数值:
function Calc(X,Y: Integer): Integer;
你可以把Calc 函数赋给变量F:
var F: function(X,Y: Integer): Integer;
F := Calc;
我们只取过程或函数头(heading)并把procedure 或function 后面的标志符去掉,剩下的就是过程类型
的名称。
可以在声明变量时直接使用这样的名称(就像上面的例子一样),也可以声明新类型:
type
TIntegerFunction = function: Integer;
TProcedure = procedure;
TStrProc = procedure(const S: string);
TMathFunc = function(X: Double): Double;
var
F: TIntegerFunction; {F 是一个无参数、返回整数值的函数}
Proc: TProcedure; { Proc 是一个无参数过程}
SP: TStrProc; { SP 是一个使用string 类型参数的过程}
M: TMathFunc; { M 是一个使用Double 类型参数、返回Double 值的函数}
procedure FuncProc(P: TIntegerFunction); { FuncProc 是一个过程,它的参数是一个无参数、返回整数值的函数}
上面的所有变量都是过程指针,也就是指向过程或函数地址的指针。若想引用一个实例对象的方法(参
考Classes and objects),你需要在过程类型的名称后面加上of object。比如
type
TMethod = procedure of object;
TNotifyEvent = procedure(Sender: TObject) of object;
这些类型表示方法指针。方法指针实际上是一对指针:第一个存储方法的地址,第二个存储方法所属的
对象的引用。给出下面的声明
type
TNotifyEvent = procedure(Sender: TObject) of object;
TMainForm = class(TForm)
procedure ButtonClick(Sender: TObject);
...
end;
var
MainForm: TMainForm;
onClick: TNotifyEvent
我们就可以进行下面的赋值:
onClick := MainForm.ButtonClick;
两个过程类型是兼容的,如果它们具有
􀁺 相同的调用约定,
􀁺 相同类型的返回值(或没有返回值),并且具有
􀁺 相同数目的参数,并且相应位置上的类型也相同(参数名无关紧要)
过程指针和方法指针是不兼容的。nil 可以赋给任何过程类型。
嵌套的过程和函数(在其它例程中声明的例程)不能被用作过程类型值,内置的过程和函数也不可以。
若想使用内置的过程作为过程类型值,比如Length,你可以给它加一个包装:
function FLength(S: string): Integer;
begin
Result := Length(S);
end;
。要比较F 和MyFunction 的过程值,使用
if @F = @MyFunction then ...;
@F 把F 转换为无类型指针变量,它包含的是地址,@MyFunction 返回的是MyFunction 的地址。
要取得过程变量的内存地址(而不是它包含的地址),使用@@。比如,@@F 返回F 的地址。
@运算符也可以用来把一个无类型指针值赋给过程变量,比如
var StrComp: function(Str1, Str2: PChar): Integer;
...
@StrComp := GetProcAddress(KernelHandle, ’lstrcmpi’);
调用GetProcAddress 函数,并使StrComp 指向结果。
要测试一个过程变量是否被赋值,使用标准函数Assigned:
if Assigned(onClick) then onClick(X);