过程类型:
声明:
type
TProc = procedure;//声明一个无参数过程类型
TFun = function : integer;//无参数返回integer函数
TProc1 = procedure(const s : string);//有参数过程类型
TFun1 = function (x: real):Real;//有参数函数
调用方法:
var
F: TFun;
P: TProc;
另外一种声明方法:
var
Func: function(x,y: integer): integer;
声明了过程类型过程变量后,就可以在赋值语句和表达式中使用该过程变量(在该变量的作用域内),或者将过程变量作为实际参数传递给某个过程或函数
eg:
从原理上讲,过程类型变量实际上为过程指针,它指向过程或函数的首地址。编译器在编译程序时,要给每一个函数或者过程分配一段内存地址。声明一个过程变量Func实际上就是声明一个过程类的指针变量Func,当执行
Func := Calc;
时,Func指向内存中函数Calc的首地址。
注意:只有满足如下条件,两个过程类型才是兼容的:
1.两个过程调用规范相同
2.具有相同的返回值类型
3.参数个数相同,并且相应位置上的参数类型也相同(参数名可以不同)
嵌套在子过程中的局部函数或过程不能作为过程值赋给过程变量,也不能用于定义过程类型。要定义过程类型,必须在程序单元的接口部分或在实现部分的隐含声明部分进行定义。
可以像其它变量一样,将具有确定值的过程或变量赋给兼容的另一个过程变量
eg:
过程变量的赋值不能使用括号。
当表达式中出现过程变量时,过程变量就表示对它指向的函数的调用。
F = Func 返回True//执行该表达式时,delphi通过变量F调用Func,执行结果与Func指向的结果进行比较
同样可写作:
F() = Func()
@@:
如果要将过程变量的值(地址)和函数或过程值(函数或过程地址)进行比较,应使用@操作符:
if @F = @Func then
@F 将F转换为一个包含地址值的无类型指针变量,而@Func返回Func函数的首地址。
要获得一个过程变量本身所占用的实际内存地址,而不是它所存储的某个过程或函数的地址,则应使用操作符@@。@@F返回F的地址。
问题:为什么一个过程类型变量要使用操作符@@才能获得自身的地址呢?
答:从Object Pascal 的语法上讲,对于过程或函数而言,它至少在程序中出现2次,一次是定义,一次是调用。编译器在解释这两次函数名时,使用不同的规范。首先,出现在function后的过程或函数名将解释为一段程序代码的首地址,而出现在其他位置的过程或函数名将解释为对该地址的引用。
当声明和使用过程类型时,为保持过程类型变量与过程或函数名的一致性,编译器将把过程类型的声明解释为一个存储指向过程或函数的指针变量,而把过程类型变量的使用解释为对该过程或函数地址的引用。
对于过程或函数名Func,@Func总是获得该过程或函数的地址,因而,对于程序代码中使用过程类型变量F的场合,@F也将获得它所代表的过程或函数的地址,@@F获得自身的地址。
声明一个过程变量F,实际上就是声明一个名为@F的指针变量,该指针变量占用32位的存储空间,他指向过程或函数的地址。而F表示对指针变量的引用,因而F相当于该指针变量的一个别名,它本身没有自己的存储空间,因此
F:=Func;
将使得指针变量@F指向Func的地址@Func
当使用@F时,总是获得它所对应的过程或函数的地址 @Func (它保存在指针变量@F中)。使用@(@F)则获得指针变量@F自身的地址。因为@操作符的右结合特性@(@F) 等价于@@F.
另外,@操作符还可以用来将无类型指针变量指派给过程变量
eg:
任何一个过程变量都可以取nil值,但试图通过具有nil值的过程变量来调用函数或过程是错误的,因为它不指向任何过程或函数。为保证在调用过程和函数前过程变量的值不为nil,则应使用 delphi 预定义的Assigned函数,在调用过程或函数前先对过程变量进行测试:if Assigned(F) then Return := F(1,2);