Delphi 函数指针(三大好处:灵活,委托的本质,回调机制),还可把函数指针当参数传入
2015-12-03 19:32
826 查看
首先学习: 指向非对象(一般的)函数/过程的函数指针
Pascal 中的过程类型与C语言中的函数指针相似,为了统一说法,以下称函数指针。函数指针的声明只需要参数列表;如果是函数,再加个返回值。例如声明一个过程类型,该类型带一个通过引用传递的整型参数:
type
IntProc = procedure (var Num: Integer);
这个过程类型与任何参数完全相同的例程兼容,即用它声明的变量,可以指向任何此类函数,并通过其进行函数的调用。下面是一个兼容例程:
函数指针能用于两种不同的目的:声明函数指针类型的变量;或者把函数指针作为参数传递给另一例程。利用上面给定的类型和过程声明,你可以写出下面的代码:
var
IP: IntProc;
X: Integer;
begin
IP := DoubleTheValue;
X := 5;
IP (X);
end;
虽然这种调用方法比直接调用麻烦了,那么我们为什么要用这种方式呢?
(1)因为在某些情况下,调用什么样的函数需要在实际中(运行时)决定,你可以根据条件来判断,实现用同一个表达,调用不同的函数,很是灵活.
(2)利用函数指针我们可以实现委托,委托在.NET中被发挥的淋漓尽致,但Delphi同样能实现
(3)实现回调机制
函数指针很有用啊,是高级程序员的必修。
例子
{********************************************************
函数指针(指向一般函数和过程)
UnitOwner:coco.zhang
Last Modified:2008-10-5
*********************************************************}
unit DelegateUnit;
interface
procedure Func1;
{定义两个函数型构相同但功能不同的函数}
function FuncAdd(VarA , VarB : Integer):Integer;
function FuncSub(VarA , VarB : Integer):Integer;
type
DelegateFunc1 = procedure;
DelegateFuncCalc = function(VarA , VarB : Integer):Integer;
var
I : Integer;
implementation
procedure Func1;
begin
Writeln('Func1 was called!');
end;
function FuncAdd(VarA , VarB : Integer):Integer;
begin
Result := VarA + VarB;
end;
function FuncSub(VarA , VarB : Integer):Integer;
begin
Result := VarA - VarB;
end;
end.
客户端调用
program Delegate;
{$APPTYPE CONSOLE}
uses
DelegateUnit;
var
ADelegateFunc1 : DelegateFunc1;
ADelegateFuncCalc : DelegateFuncCalc;
begin
{通过函数指针调用过程}
ADelegateFunc1 := Func1;
ADelegateFunc1 ;
{通过同种方式调用不同函数}
ADelegateFuncCalc := FuncAdd;
Writeln(ADelegateFuncCalc(3,5));
ADelegateFuncCalc := FuncSub;
Writeln(ADelegateFuncCalc(3,5));
end.
运行结果
D:\Projects\Delphi7\src\GofProjects\Delegate>Delegate
Func1 was called!
8
-2 http://www.cnblogs.com/fengyuwuzu1980/archive/2008/12/23/1360268.html --------------------------------------------------------------------------------------------------------
type
TFunctionParameter = function(const value : integer) : string;
2) 定义准备被作为参数传递的函数
function One(const value : integer) : string;
begin
result := IntToStr(value) ;
end;
function Two(const value : integer) : string;
begin
result := IntToStr(2 * value) ;
end;
3) 定义将要使用动态函数指针参数的函数
function DynamicFunction(f : TFunctionParameter; const value : integer) : string;
begin
result := f(value) ;
end;
4) 上面这个动态函数的使用实例
var
s : string;
begin
s := DynamicFunction(One,2006) ;
ShowMessage(s) ; //will display "2006"
s := DynamicFunction(Two,2006) ;
ShowMessage(s) ; // will display "4012"
end;
一个指向函数的指针在赋值指向函数时,不需要显示地取函数的地址。
例:
var F:function(X:Integer):Integer;
...
function aa(X:Integer):Integer;
不需要: F:=^aa;
只要:F:=aa;就可以了。
F:=aa可能是一个函数类型变量赋值,也可能是调用aa函数过程。
如果F不是一个函数过程类型,它就是一个函数调用。
但是只要是出现在表达式中,就一定是函数过程的调用。
例:if A:=fun then
A:=fun一定是一个函数过程的调用,将返回值赋予A
注意,如果fun是一个过程(它没有返回值)或它需要参数(需要写上参数),那就会产生语法错误。
如果要显示说明它是一个赋值语句而不是函数过程的调用,可以这样写
if @A :=@fun then
@A是将A转换成一个无类型指针(它本身就是以指针形式存在)
@fun是取得函数过程fun的地址
可以通过@@A的方式取得该过程函数变量的地址,而不是它指向的函数过程的地址
void SetProcessDataProc(NOTISFYDATAISRECEIVED ProcessDataProc)
参数:ProcessDataProc —— 回调函数指针。
返回值:无
功能:设置数据到达通知函数。动态连接库主动通知用户有新数据到达,随后用户就可以立即查询相关数据。用户调用此接口函数设置通知函数以后,每当新数据到达,动态连接库就通过这个通知函数通知用户。通知函数原型必须如下:(函数名称和参数名称可以不同)
void ProcessDataProc(int iBedNo,unsigned char ucDataType,WPARAM wParam);
其中,iBedNo参数表示到达数据所对应的设备号。
ucDataType表示到达数据类型。ucDataType值与对应的数据包类型以及常调用的接口函数如表1所示。对于表中没有列举的数据包类型,数据包内没有有用的数据。
wParam用于传递其他信息,保留,暂时没有使用。
所以,SetProcessDataProc接口函数的参数类型NOTISFYDATAISRECEIVED可以定义如下:
typedef void(* NOTISFYDATAISRECEIVED)(int iBedNo,unsigned char ucDataType,WPARAM wParam);
这是一个动态连接库中一个函数,我现在想在delphi中调用该函数,请问该如何定义上述类型和函数。
void ProcessDataProc(int iBedNo,unsigned char ucDataType,WPARAM wParam);
->
procedure ProcessDataProc(iBedNo: Integer; ucDataType:BYTE; wParam: WPARAM);stdcall;
typedef void(* NOTISFYDATAISRECEIVED)(int iBedNo,unsigned char ucDataType,WPARAM wParam);
->
type NOTISFYDATAISRECEIVED = procedure of(iBedNo: Integer; ucDataType:BYTE; wParam: WPARAM) of object;///
Pascal 中的过程类型与C语言中的函数指针相似,为了统一说法,以下称函数指针。函数指针的声明只需要参数列表;如果是函数,再加个返回值。例如声明一个过程类型,该类型带一个通过引用传递的整型参数:
type
IntProc = procedure (var Num: Integer);
这个过程类型与任何参数完全相同的例程兼容,即用它声明的变量,可以指向任何此类函数,并通过其进行函数的调用。下面是一个兼容例程:
procedure DoubleTheValue (var Value: Integer); begin Value := Value * 2; end;
函数指针能用于两种不同的目的:声明函数指针类型的变量;或者把函数指针作为参数传递给另一例程。利用上面给定的类型和过程声明,你可以写出下面的代码:
var
IP: IntProc;
X: Integer;
begin
IP := DoubleTheValue;
X := 5;
IP (X);
end;
虽然这种调用方法比直接调用麻烦了,那么我们为什么要用这种方式呢?
(1)因为在某些情况下,调用什么样的函数需要在实际中(运行时)决定,你可以根据条件来判断,实现用同一个表达,调用不同的函数,很是灵活.
(2)利用函数指针我们可以实现委托,委托在.NET中被发挥的淋漓尽致,但Delphi同样能实现
(3)实现回调机制
函数指针很有用啊,是高级程序员的必修。
例子
{********************************************************
函数指针(指向一般函数和过程)
UnitOwner:coco.zhang
Last Modified:2008-10-5
*********************************************************}
unit DelegateUnit;
interface
procedure Func1;
{定义两个函数型构相同但功能不同的函数}
function FuncAdd(VarA , VarB : Integer):Integer;
function FuncSub(VarA , VarB : Integer):Integer;
type
DelegateFunc1 = procedure;
DelegateFuncCalc = function(VarA , VarB : Integer):Integer;
var
I : Integer;
implementation
procedure Func1;
begin
Writeln('Func1 was called!');
end;
function FuncAdd(VarA , VarB : Integer):Integer;
begin
Result := VarA + VarB;
end;
function FuncSub(VarA , VarB : Integer):Integer;
begin
Result := VarA - VarB;
end;
end.
客户端调用
program Delegate;
{$APPTYPE CONSOLE}
uses
DelegateUnit;
var
ADelegateFunc1 : DelegateFunc1;
ADelegateFuncCalc : DelegateFuncCalc;
begin
{通过函数指针调用过程}
ADelegateFunc1 := Func1;
ADelegateFunc1 ;
{通过同种方式调用不同函数}
ADelegateFuncCalc := FuncAdd;
Writeln(ADelegateFuncCalc(3,5));
ADelegateFuncCalc := FuncSub;
Writeln(ADelegateFuncCalc(3,5));
end.
运行结果
D:\Projects\Delphi7\src\GofProjects\Delegate>Delegate
Func1 was called!
8
-2 http://www.cnblogs.com/fengyuwuzu1980/archive/2008/12/23/1360268.html --------------------------------------------------------------------------------------------------------
Delphi函数指针的使用
geek_loser 发布于 1年前,共有 0 条评论delphi中可以通过函数指针把一个函数作为参数来传递,然后在另外一个函数中调用。
1) 首先,申明函数指针类型TFunctionParameter。type
TFunctionParameter = function(const value : integer) : string;
2) 定义准备被作为参数传递的函数
function One(const value : integer) : string;
begin
result := IntToStr(value) ;
end;
function Two(const value : integer) : string;
begin
result := IntToStr(2 * value) ;
end;
3) 定义将要使用动态函数指针参数的函数
function DynamicFunction(f : TFunctionParameter; const value : integer) : string;
begin
result := f(value) ;
end;
4) 上面这个动态函数的使用实例
var
s : string;
begin
s := DynamicFunction(One,2006) ;
ShowMessage(s) ; //will display "2006"
s := DynamicFunction(Two,2006) ;
ShowMessage(s) ; // will display "4012"
end;
一个指向函数的指针在赋值指向函数时,不需要显示地取函数的地址。
例:
var F:function(X:Integer):Integer;
...
function aa(X:Integer):Integer;
不需要: F:=^aa;
只要:F:=aa;就可以了。
F:=aa可能是一个函数类型变量赋值,也可能是调用aa函数过程。
如果F不是一个函数过程类型,它就是一个函数调用。
但是只要是出现在表达式中,就一定是函数过程的调用。
例:if A:=fun then
A:=fun一定是一个函数过程的调用,将返回值赋予A
注意,如果fun是一个过程(它没有返回值)或它需要参数(需要写上参数),那就会产生语法错误。
如果要显示说明它是一个赋值语句而不是函数过程的调用,可以这样写
if @A :=@fun then
@A是将A转换成一个无类型指针(它本身就是以指针形式存在)
@fun是取得函数过程fun的地址
可以通过@@A的方式取得该过程函数变量的地址,而不是它指向的函数过程的地址
void SetProcessDataProc(NOTISFYDATAISRECEIVED ProcessDataProc)
参数:ProcessDataProc —— 回调函数指针。
返回值:无
功能:设置数据到达通知函数。动态连接库主动通知用户有新数据到达,随后用户就可以立即查询相关数据。用户调用此接口函数设置通知函数以后,每当新数据到达,动态连接库就通过这个通知函数通知用户。通知函数原型必须如下:(函数名称和参数名称可以不同)
void ProcessDataProc(int iBedNo,unsigned char ucDataType,WPARAM wParam);
其中,iBedNo参数表示到达数据所对应的设备号。
ucDataType表示到达数据类型。ucDataType值与对应的数据包类型以及常调用的接口函数如表1所示。对于表中没有列举的数据包类型,数据包内没有有用的数据。
wParam用于传递其他信息,保留,暂时没有使用。
所以,SetProcessDataProc接口函数的参数类型NOTISFYDATAISRECEIVED可以定义如下:
typedef void(* NOTISFYDATAISRECEIVED)(int iBedNo,unsigned char ucDataType,WPARAM wParam);
这是一个动态连接库中一个函数,我现在想在delphi中调用该函数,请问该如何定义上述类型和函数。
void ProcessDataProc(int iBedNo,unsigned char ucDataType,WPARAM wParam);
->
procedure ProcessDataProc(iBedNo: Integer; ucDataType:BYTE; wParam: WPARAM);stdcall;
typedef void(* NOTISFYDATAISRECEIVED)(int iBedNo,unsigned char ucDataType,WPARAM wParam);
->
type NOTISFYDATAISRECEIVED = procedure of(iBedNo: Integer; ucDataType:BYTE; wParam: WPARAM) of object;///
相关文章推荐
- Delphi获取本机的MAC地址
- delphi读取和写入文件-richedit控件
- Delphi下POS机
- Android问题-DelphiXE8安装后编译Android提示SDK无法更新问题(XE10也可以解决)
- 自写的LastPos,寻找字符串里的最后一个字符,RTL里没有提供这个函数——Delphi的String下标是从1开始的
- 怎样在DELPHI中使用API函数
- 怎样在DELPHI中使用API函数
- Delphi字段类型和不同数据库对应.txt
- Delphi与SQL模糊like通配符查询(转载)
- Delphi通过IE窗口句柄获取网页接口(IWebBrowser2) good
- Delphi中的Rtti函数
- 强大的DELPHI RTTI–兼谈需要了解多种开发语言
- Delphi中运行时改变panel的位置及大小(WM_SysCommand消息配合参数使用,很奇妙) good
- Delphi判断一个文件是不是JPG图片
- delphi中覆盖最大化消息(WM_GETMINMAXINFO)
- Delphi中TWebBrowser中注入Js
- delphi写的整合汇编与api的简单的窗口程序
- Delphi中methodaddress的汇编代码解析
- delphi程序设计之底层原理
- Delphi中TFlowPanel实现滚动条效果