上一题下一题
跳转到
 
 
  世界如此多姿,发展如此迅速,窥一斑未必还能知全豹。但正如万花筒一样,每一个管窥都色彩斑斓。  
 
 
  知识通道 | 学习首页 | 教师首页 | PK首页 | 知识创造首页 | 企业首页 | 登录
 
本文对应知识领域
DELPHI语法编程基础(9)
作者:未知 申领版权
2010年12月12日 共有 2048 次访问 【添加到收藏夹】 【我要附加题目
受欢迎度:

    过程类型 
    Object Pascal 的另一个独特功能是可定义过程类型。过程类型属于语言的高级功能,Delphi 程序员不会经常用到它。
    Pascal 中的过程类型与C语言中的函数指针相似。过程类型的声明只需要参数列表;如果是函数,再加个返回值。例如声明一个过程类型,该类型带一个通过引用传递的整型参数:
    type
    IntProc = procedure (var Num: Integer);
    这个过程类型与任何参数完全相同的例程兼容(或用C语言行话来说,具有相同的函数特征)。下面是一个兼容例程:
    procedure DoubleTheValue (var Value: Integer);
    begin
    Value := Value * 2;
    end;
    注意:在16位Delphi中,如果要将例程用作过程类型的实际值,必须用far指令声明该例程。
    过程类型能用于两种不同的目的:声明过程类型的变量;或者把过程类型(也就是函数指针)作为参数传递给另一例程。利用上面给定的类型和过程声明,你可以写出下面的代码:
    var
    IP: IntProc;
    X: Integer;
    begin
    IP := DoubleTheValue;
    X := 5;
    IP (X);
    end;
    这段代码与下列代码等效:
    var
    X: Integer;
    begin
    X := 5;
    DoubleTheValue (X);
    end;
    上面第一段代码明显要复杂一些,那么我们为什么要用它呢?因为在某些情况下,调用什么样的函数需要在实际中决定,此时程序类型就很有用。这里不可能建立一个复杂的例子来说明这个问题,不过可以探究一下简单点的例子,该例名为ProcType。该例比前面所举的例子都复杂,更接近实际应用。
    如图6.3所示,新建一个工程,在上面放两个radio按钮和一个push按钮。例中有两个过程,一个过程使参数的值加倍,与前面的DoubleTheValue过程相似;另一个过程使参数的值变成三倍,因此命名为TripleTheValue
    图 6.3: 例 ProcType 窗体 
    
    procedure TripleTheValue (var Value: Integer);
    begin
    Value := Value * 3;
    ShowMessage ('Value tripled: '   IntToStr (Value));
    end;
    两个过程都有结果显示,让我们知道他们已被调用。这是一个简单的程序调试技巧,你可以用它来检测某一代码段是否或何时被执行,而不用在代码中加断点。
    当用户按Apply 按钮,程序会根据radio按钮状态选择执行的过程。实际上,当窗体中有两个radio按钮时,你只能选择一个,因此你只需要在Apply 按钮的OnClick 事件中添加代码检测radio按钮的值,就能实现程序要求。不过为了演示过程类型的使用,我舍近求远选择了麻烦但有趣的方法:只要用户选中其中一个radio按钮,按钮对应的过程就会存入过程变量:
    procedure TForm1.DoubleRadioButtonClick(Sender: TObject);
    begin
    IP := DoubleTheValue;
    end;
    当用户按Apply 按钮,程序就执行过程变量保存的过程:
    procedure TForm1.ApplyButtonClick(Sender: TObject);
    begin
    IP (X);
    end;
    为了使三个不同的函数能访问IP和 X变量,需要使变量在整个窗体单元中可见,因此不能声明为局部变量(在一个方法中声明)。一个解决办法是,把这些变量放在窗体声明中:
    type
    TForm1 = class(TForm)
    ...
    private
    { Private declarations }
    IP: IntProc;
    X: Integer;
    end;
    函数重载 
    重载的思想很简单:编译器允许你用同一名字定义多个函数或过程,只要它们所带的参数不同。实际上,编译器是通过检测参数来确定需要调用的例程。
    下面是从VCL的数学单元(Math Unit)中摘录的一系列函数:
    function Min (A,B: Integer): Integer; overload;
    function Min (A,B: Int64): Int64; overload;
    function Min (A,B: Single): Single; overload;
    function Min (A,B: Double): Double; overload;
    function Min (A,B: Extended): Extended; overload;
    当调用方式为Min (10, 20)时,编译器很容易就能判定你调用的是上列第一个函数,因此返回值也是个整数。
    声明重载函数有两条原则:
    · 每个例程声明后面必须添加overload 关键字。 
    · 例程间的参数个数或(和)参数类型必须不同,返回值不能用于区分各例程。 
    下面是ShowMsg 过程的三个重载过程。我已把它们添加到例OverDef 中(一个说明重载和确省参数的应用程序):
    procedure ShowMsg (str: string); overload;
    begin
    MessageDlg (str, mtInformation, [mbOK], 0);
    end;
    
    procedure ShowMsg (FormatStr: string;
    Params: array of const); overload;
    begin
    MessageDlg (Format (FormatStr, Params),
    mtInformation, [mbOK], 0);
    end;
    
    procedure ShowMsg (I: Integer; Str: string); overload;
    begin
    ShowMsg (IntToStr (I)   ' '   Str);
    end;
    三个过程分别用三种不同的方法格式化字符串,然后在信息框中显示字符串。下面是三个例程的调用:
    ShowMsg ('Hello');
    ShowMsg ('Total = %d.', [100]);
    ShowMsg (10, 'MBytes');
    当你在例程名后面键入左圆括号时,窗口中会显示所有可用例程的参数列表,当你输入参数时,Delphi会根据所输入参数的类型过滤参数列表。从图6.4你可看到,当开始输入一个常量字符串时,Delphi只显示第一个参数为字符串的两个ShowMsg例程参数列表,滤掉了第一个参数为整数的例程。
    图 6.4: 窗口中代码参数提示条显示的重载例程参数 
    
    重载例程必须用overload关键字明确标示,你不能在同一单元中重载没有overload标示的例程,否则会出现错误信息: "Previous declaration of '<name>' was not marked with the 'overload' directive."。不过你可以重载在其他单元中声明的例程,这是为了与以前的Delphi版本兼容,以前的Delphi版本允许不同的单元重用相同的例程名。无论如何,这是例程重载的特殊情况不是其特殊功能,而且不小心会出现问题。
    例如在一个单元中添加以下代码:
    procedure MessageDlg (str: string); overload;
    begin
    Dialogs.MessageDlg (str, mtInformation, [mbOK], 0);
    end;
    这段代码并没有真正重载原始的MessageDlg 例程,实际上如果键入:
    MessageDlg ('Hello');
    你将得到一个有意思的错误消息,告诉你缺少参数。调用本地例程而不是VCL的唯一途径是明确标示例程所在单元,这有悖于例程重载的思想:
    OverDefF.MessageDlg ('Hello');
    确省参数 
    Delphi允许你给函数的参数设定确省值,这样调用函数时该参数可以加上,也可以省略。下例把应用程序全程对象的MessageBox 方法重新包装了一下,用PChar 替代字符串,并设定两个确省值:
    procedure MessBox (Msg: string;
    Caption: string = 'Warning';
    Flags: LongInt = mb_OK or mb_IconHand);
    begin
    Application.MessageBox (PChar (Msg),
    PChar (Caption), Flags);
    end;
    使用这一定义,你就可以用下面任一种方式调用过程:
    MessBox ('Something wrong here!');
    MessBox ('Something wrong here!', 'Attention');
    MessBox ('Hello', 'Message', mb_OK);
    从图6.5中可以看到,Delphi的代码参数提示条会用不同的风格显示确省值参数,这样你就很容易确定哪个参数是可以省略的。
    图 6.5: Delphi代码参数提示条用方括号标示确省值参数,调用时可以省略该参数 
    
    注意一点,Delphi 不产生任何支持确省参数的特殊代码,也不创建例程的多份拷贝,缺省参数是由编译器在编译时添加到调用例程的代码中。
    使用确省参数有一重要限定:你不能“跳过”参数,如省略第二个参数后,不能把第三个参数传给函数:
    MessBox ('Hello', mb_OK); // error  
    确省参数使用主要规则:调用时你只能从最后一个参数开始进行省略,换句话说,如果你要省略一个参数,你必须省略它后面所有的参数。
    确省参数的使用规则还包括:
    · 带确省值的参数必须放在参数表的最后面。 
    · 确省值必须是常量。显然,这限制了确省参数的数据类型,例如动态数组和界面类型的确省参数值只能是 nil;至于记录类型,则根本不能用作确省参数。 
    · 确省参数必须通过值参或常参传递。引用参数 var不能有缺省值。 
    如果同时使用确省参数和重载可能会出现问题,因为这两种功能可能发生冲突。例如把以前ShowMsg 过程改成:
    procedure ShowMsg (Str: string; I: Integer = 0); overload;
    begin
    MessageDlg (Str   ': '   IntToStr (I),
    mtInformation, [mbOK], 0);
    end;
    编译时编译器不会提出警告,因为这是合法的定义。
    然而编译调用语句:
    ShowMsg ('Hello');
    编译器会显示 Ambiguous overloaded call to 'ShowMsg'.( 不明确重载调用ShowMsg)。注意,这条错误信息指向新定义的重载例程代码行之前。实际上,用一个字符串参数无法调用ShowMsg 过程,因为编译器搞不清楚你是要调用只带字符串参数的ShowMsg 过程,还是带字符串及整型确省参数的过程。遇到这种问题时,编译器不得不停下来,要求你明确自己的意图。
    字符串类型 
    在Borland公司的Turbo Pascal和16位Delphi中,传统的字符串类型是一个字符序列,序列的头部是一个长度字节,指示当前字符串的长度。由于只用一个字节来表示字符串的长度,所以字符串不能超过255个字符。这一长度限制为字符串操作带来不便,因为每个字符串必须定长(确省最大值为255),当然你也可以声明更短的字符串以节约存储空间。
    字符串类型与数组类型相似。实际上一个字符串差不多就是一个字符类型的数组,因为用[]符号,你就能访问字符串中的字符,这一事实充分说明了上述观点。
    为克服传统Pascal 字符串的局限性,32位Delphi增加了对长字符串的支持。这样共有三种字符串类型:
    · ShortString 短字符串类型也就是前面所述的传统 Pascal 字符串类型。这类字符串最多只能有255个字符,与16位Delphi中的字符串相同。短字符串中的每个字符都属于ANSIChar 类型(标准字符类型)。 
    · ANSIString长字符串类型就是新增的可变长字符串类型。这类字符串的内存动态分配,引用计数,并使用了更新前拷贝(copy-on-write)技术。这类字符串长度没有限制(可以存储多达20亿个字符!),其字符类型也是ANSIChar 类型。 
    · WideString 长字符串类型与ANSIString 类型相似,只是它基于WideChar 字符类型,WideChar 字符为双字节Unicode 字符。 
    使用长字符串 
    如果只简单地用String定义字符串,那么该字符串可能是短字符串也可能是ANSI长字符串,这取决于$H 编译指令的值,$H (确省)代表长字符串(ANSIString 类型)。长字符串是Delphi 库中控件使用的字符串。
    Delphi 长字符串基于引用计数机制,通过引用计数追踪内存中引用同一字符串的字符串变量,当字符串不再使用时,也就是说引用计数为零时,释放内存。
    如果你要增加字符串的长度,而该字符串邻近又没有空闲的内存,即在同一存储单元字符串已没有扩展的余地,这时字符串必须被完整地拷贝到另一个存储单元。当这种情况发生时,Delphi运行时间支持程序会以完全透明的方式为字符串重新分配内存。为了有效地分配所需的存储空间,你可以用SetLength 过程设定字符串的最大长度值:
    SetLength (String1, 200);
    SetLength 过程只是完成一个内存请求,并没有实际分配内存。它只是把将来所需的内存预留出来,实际上并没有使用这段内存。这一技术源于Windows 操作系统,现被Delphi用来动态分配内存。例如,当你请求一个很大的数组时,系统会将数组内存预留出来,但并没有把内存分配给数组。
    一般不需要设置字符串的长度,不过当需要把长字符串作为参数传递给API 函数时(经过类型转换后),你必须用SetLength 为该字符串预留内存空间。

    

 

相关新闻

每一个程序员要遵守的一些优秀编程风格
代词it, that, one, the one 的辨析
《VB程序设计基础》选择题
Is Family Life Changing
设计模式之Iterator
设计模式之Visitor
设计模式之Interpreter(解释器)
设计模式之Mediator(中介者)
设计模式之Strategy(策略)
设计模式之State

您可能对这些感兴趣  

第7讲 综合分析BIM在运用与推广中的障碍问题
考核学生质量的困难
日本福岛核电站事故初步分析
论科技异化与科技人化
中国科技计划项目管理现状与对策
财政科技资金的审计重点和内容
软科学研究机构在政府决策中的功效、困境及对策研究
打造超级DOS系统(下)
DOS命令基础应用(6)
打造超级DOS系统(上)

题目筛选器
日期:
类型:
状态:
得分: <=
分类:
作者:
职业:
关键字:
搜索

 
 
 
  焦点事件
 
  知识体系
 
  职业列表
 
 
  最热文章
 
 
  最多引用文章
 
 
  最新文章
 
 
 
 
网站介绍 | 广告服务 | 招聘信息 | 保护隐私权 | 免责条款 | 法律顾问 | 意见反馈
版权所有 不得转载
沪ICP备 10203777 号 联系电话:021-54428255
  帮助提示    
《我的太学》是一种全新的应用,您在操作中遇到疑问或者问题,请拨打电话13564659895,15921448526。
《我的太学》