ImageVerifierCode 换一换
格式:DOCX , 页数:20 ,大小:71.91KB ,
资源ID:9657200      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/9657200.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(pascal语言中的过程与函数.docx)为本站会员(b****8)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

pascal语言中的过程与函数.docx

1、pascal语言中的过程与函数Pascal 过程与函数 Pascal中的例程有两种形式:过程和函数。理论上说,过程是你要求计算机执行的操作,函数是能返回值的计算。两者突出的不同点在于:函数能返回计算结果,即有一个返回值,而过程没有。两种类型的例程都可以带多个给定类型的参数。不过实际上函数和过程差别不大,因为你可以调用函数完成一系列操作,跳过其返回值(用可选的出错代码或类似的东西代替返回值);也可以通过过程的参数传递计算结果(这种参数称为引用,下一部分会讲到)。下例定义了一个过程、两个函数,两个函数的语法略有不同,结果是完全相同的。procedure Hello;begin ShowMessag

2、e (Hello world!);end;function Double (Value: Integer) : Integer;begin Double := Value * 2;end;/ or, as an alternativefunction Double2 (Value: Integer) : Integer;begin Result := Value * 2;end;流行的做法是用Result 给函数赋返回值,而不是用函数名,我认为这样的代码更易读。一旦定义了这些例程,你就可以多次调用,其中调用过程可执行操作;调用函数能计算返回值。如下:procedure TForm1.Butto

3、n1Click (Sender: TObject);begin Hello;end; procedure TForm1.Button2Click (Sender: TObject);var X, Y: Integer;begin X := Double (StrToInt (Edit1.Text); Y := Double (X); ShowMessage (IntToStr (Y);end;注意:现在不必考虑上面两个过程的语法,实际上它们是方法。只要把两个按钮(button)放到一个Delphi 窗体上,在设计阶段单击它们,Delphi IDE将产生合适的支持代码,你只需要填上begin 和

4、end 之间的那几行代码就行。编译上面的代码,需要你在窗体中加一个Edit控件。现在回到我前面提到过的代码封装概念。当你调用Double 函数时,你不需要知道该函数的具体实现方法。如果以后发现了更好的双倍数计算方法,你只需要改变函数的代码,而调用函数的代码不必改变(尽管代码执行速度可能会加快!)。Hello 过程也一样,你可以通过改变这个过程的代码,修改程序的输出,Button2Click 方法会自动改变显示结果。下面是改变后的代码:procedure Hello;begin MessageDlg (Hello world!, mtInformation, mbOK);end;提示:当调用一个

5、现有的Delphi 函数、过程或任何VCL方法时,你应该记住参数的个数及其数据类型。不过,只要键入函数或过程名及左括号,Delphi 编辑器中会出现即时提示条,列出函数或过程的参数表供参考。这一特性被称为代码参数(Code Parameters) ,是代码识别技术的一部分。引用参数 Pascal 例程的传递参数可以是值参也可以是引用参数。值参传递是缺省的参数传递方式:即将值参的拷贝压入栈中,例程使用、操纵的是栈中的拷贝值,不是原始值。当通过引用传递参数时,没有按正常方式把参数值的拷贝压栈(避免拷贝值压栈一般能加快程序执行速度),而是直接引用参数原始值,例程中的代码也同样访问原始值,这样就能在过

6、程或函数中改变参数的值。引用参数用关键字var 标示。参数引用技术在大多数编程语言中都有,C语言中虽没有,但C+中引入了该技术。在C+中,用符号 &表示引用;在VB中,没有ByVal 标示的参数都为引用。下面是利用引用传递参数的例子,引用参数用var关键字标示:procedure DoubleTheValue (var Value: Integer);begin Value := Value * 2;end;在这种情况下,参数既把一个值传递给过程,又把新值返回给调用过程的代码。当你执行完以下代码时:var X: Integer;begin X := 10; DoubleTheValue (X)

7、;x变量的值变成了20,因为过程通过引用访问了X的原始存储单元,由此改变了X的初始值。通过引用传递参数对有序类型、传统字符串类型及大型记录类型才有意义。实际上Delphi总是通过值来传递对象,因为Delphi对象本身就是引用。因此通过引用传递对象就没什么意义(除了极特殊的情况),因为这样相当于传递一个引用到另一个引用。Delphi 长字符串的情况略有不同,长字符串看起来象引用,但是如果你改变了该字符串的串变量,那么这个串在更新前将被拷贝下来。作为值参被传递的长字符串只在内存使用和操作速度方面才象引用,但是如果你改变了字符串的值,初始值将不受影响。相反,如果通过引用传递长字符串,那么串的初始值就

8、可以改变。Delphi 3增加了一种新的参数:out。out参数没有初始值,只是用来返回一个值。out参数应只用于COM过程和函数,一般情况下最好使用更有效的var参数。除了没有初始值这一点之外,out参数与var参数相同。常量参数 除了引用参数外,还有一种参数叫常量参数。由于不允许在例程中给常量参数赋新值,因此编译器能优化常参的传递过程。编译器会选用一种与引用参数相似的方法编译常参(C+术语中的常量引用),但是从表面上看常参又与值参相似,因为常参初始值不受例程的影响。事实上,如果编译下面有点可笑的代码,Delphi将出现错误:function DoubleTheValue (const Va

9、lue: Integer): Integer;begin Value := Value * 2; / compiler error Result := Value;end;开放数组参数 与C语言不同,Pascal 函数及过程的参数个数是预定的。如果参数个数预先没有确定,则需要通过开放数组来实现参数传递。一个开放数组参数就是一个固定类型开放数组的元素。 也就是说,参数类型已定义,但是数组中的元素个数是未知数。见下例:function Sum (const A: array of Integer): Integer;var I: Integer;begin Result := 0; for I :

10、= Low(A) to High(A) do Result := Result + AI;end;上面通过High(A)获取数组的大小,注意其中函数返回值 Result的应用, Result用来存储临时值。你可通过一个整数表达式组成的数组来调用该函数:X := Sum (10, Y, 27*I);给定一个整型数组,数组大小任意,你可以直接把它传递给带开放数组参数的例程,此外你也可以通过Slice 函数,只传递数组的一部分元素(传递元素个数由Slice 函数的第二个参数指定)。下面是传递整个数组参数的例子:var List: array 1.10 of Integer; X, I: Intege

11、r;begin / initialize the array for I := Low (List) to High (List) do List I := I * 2; / call X := Sum (List);如果你只传递数组的一部分,可使用Slice 函数,如下:X := Sum (Slice (List, 5);例OpenArr中可见到包括上面的完整代码(见图6.1)。图 6.1: 单击 Partial Slice 按钮显示的结果 在Delphi 4中,给定类型的开放数组与动态数组完全兼容(动态数组将在第8章中介绍)。动态数组的语法与开放数组相同,区别在于你可以用诸如array o

12、f Integer指令定义变量,而不仅仅是传递参数。类型变化的开放数组参数 除了类型固定的开放数组外,Delphi 还允许定义类型变化的甚至无类型的开放数组。这种特殊类型的数组元素可随意变化,能很方便地用作传递参数。技术上,array of const 类型的数组就能实现把不同类型、不同个数元素组成的数组一下子传递给例程。如下面Format 函数的定义(第七章中你将看到怎样使用这个函数):function Format (const Format: string; const Args: array of const): string;上面第二个参数是个开放数组,该数组元素可随意变化。如你可以

13、按以下方式调用这个函数:N := 20;S := Total:;Label1.Caption := Format (Total: %d, N);Label2.Caption := Format (Int: %d, Float: %f, N, 12.4);Label3.Caption := Format (%s %d, S, N * 2);从上可见,传递的参数可以是常量值、变量值或一个表达式。声明这类函数很简单,但是怎样编写函数代码呢?怎样知道参数类型呢?对类型可变的开放数组,其数组元素与TVarRec 类型元素兼容。注意:不要把TVarRec 记录类型和Variant 类型使用的TVarDat

14、a 记录类型相混淆。这两种类型用途不同,而且互不兼容。甚至可容纳的数据类型也不同,因为TVarRec 支持Delphi 数据类型,而TVarData 支持OLE 数据类型。TVarRec 记录类型结构如下:type TVarRec = record case Byte of vtInteger: (VInteger: Integer; VType: Byte); vtBoolean: (VBoolean: Boolean); vtChar: (VChar: Char); vtExtended: (VExtended: PExtended); vtString: (VString: PShort

15、String); vtPointer: (VPointer: Pointer); vtPChar: (VPChar: PChar); vtObject: (VObject: TObject); vtClass: (VClass: TClass); vtWideChar: (VWideChar: WideChar); vtPWideChar: (VPWideChar: PWideChar); vtAnsiString: (VAnsiString: Pointer); vtCurrency: (VCurrency: PCurrency); vtVariant: (VVariant: PVarian

16、t); vtInterface: (VInterface: Pointer); end;每种记录都有一个VType 域,乍一看不容易发现,因为它与实际意义的整型类型数据(通常是一个引用或一个指针)放在一起,只被声明了一次。利用上面信息我们就可以写一个能操作不同类型数据的函数。下例的SumAll 函数,通过把字符串转成整数、字符转成相应的序号、True布尔值加一,计算不同类型数据的和。这段代码以一个case语句为基础,虽然不得不经常通过指针取值,但相当简单,:function SumAll (const Args: array of const): Extended;var I: Integer

17、;begin Result := 0; for I := Low(Args) to High (Args) do case Args I.VType of vtInteger: Result := Result + Args I.VInteger; vtBoolean: if Args I.VBoolean then Result := Result + 1; vtChar: Result := Result + Ord (Args I.VChar); vtExtended: Result := Result + Args I.VExtended; vtString, vtAnsiString

18、: Result := Result + StrToIntDef (Args I.VString), 0); vtWideChar: Result := Result + Ord (Args I.VWideChar); vtCurrency: Result := Result + Args I.VCurrency; end; / caseend;我已在例OpenArr中加了这段代码,该例在按下设定的按钮后调用SumAll 函数。procedure TForm1.Button4Click(Sender: TObject);var X: Extended; Y: Integer;begin Y :

19、= 10; X := SumAll (Y * Y, k, True, 10.34, 99999); ShowMessage (Format ( SumAll (Y*Y, k, True, 10.34, 99999) = %n, X);end;在图6.2中,你可以看到调用函数的输出和例OpenArr的窗体。图 6.2: 例OpenArr的窗体,当按Untype按钮出现的信息框 Delphi 调用协定 32位的Delphi 中增加了新的参数传递方法,称为fastcall:只要有可能,传递到CPU寄存器的参数能多达三个,使函数调用操作更快。这种快速调用协定(Delphi 3确省方式)可用regist

20、er 关键字标示。问题是这种快速调用协定与Windows不兼容,Win32 API 函数必须声明使用stdcall 调用协定。这种协定是Win16 API使用的原始Pascal 调用协定和C语言使用的cdecl 调用协定的混合体。除非你要调用外部Windows函数或定义Windows 回调函数,否则你没有理由不用新增的快速调用协定。 在后面你会看到使用stdcall 协定的例子,在Delphi帮助文件的Calling conventions 主题下,你能找到有关Delphi调用协定的总结内容。什么是方法? 如果你使用过Delphi 或读过Delphi 手册,大概已经听说过“方法”这个术语。方法

21、是一种特殊的函数或过程,它与类这一数据类型相对应。在Delphi 中,每处理一个事件,都需要定义一个方法,该方法通常是个过程。不过一般“方法”是指与类相关的函数和过程。你已经在本章和前几章中看到了几个方法。下面是Delphi 自动添加到窗体源代码中的一个空方法:procedure TForm1.Button1Click(Sender: TObject);begin here goes your codeend;Forward 声明 当使用一个标识符(任何类型)时,编译器必须已经知道该标识符指的是什么。为此,你通常需要在例程使用之前提供一个完整的声明。然而在某些情况下可能做不到这一点,例如过程A

22、调用过程B,而过程B又调用过程A,那么你写过程代码时,不得不调用编译器尚未看到其声明的例程。欲声明一个过程或函数,而且只给出它的名字和参数,不列出其实现代码,需要在句尾加forward 关键字:procedure Hello; forward;在后面应该补上该过程的完整代码,不过该过程代码的位置不影响对它的调用。下面的例子没什么实际意义,看过后你会对上述概念有所认识:procedure DoubleHello; forward;procedure Hello;begin if MessageDlg (Do you want a double message?, mtConfirmation,

23、mbYes, mbNo, 0) = mrYes then DoubleHello else ShowMessage (Hello);end;procedure DoubleHello;begin Hello; Hello;end;上述方法可用来写递归调用:即DoubleHello 调用Hello,而Hello也可能调用DoubleHello。当然,必须设置条件终止这个递归,避免栈的溢出。上面的代码可以在例DoubleH 中找到,只是稍有改动。尽管 forward 过程声明在Delphi中不常见,但是有一个类似的情况却经常出现。当你在一个单元(关于单元的更多内容见下一章)的interface 部

24、分声明一个过程或一个函数时,它被认为是一个forward声明,即使没有forward关键字也一样。实际上你不可能把整个例程的代码放在interface 部分,不过你必须在同一单元中提供所声明例程的实现。类内部的方法声明也同样是forward声明,当你给窗体或其组件添加事件时, Delphi会自动产生相应的代码。在TForm 类中声明的事件是forward 声明,事件代码放在单元的实现部分。下面摘录的源代码中有一个Button1Click 方法声明:type TForm1 = class(TForm) ListBox1: TListBox; Button1: TButton; procedure

25、 Button1Click(Sender: TObject); end;过程类型 Object Pascal 的另一个独特功能是可定义过程类型。过程类型属于语言的高级功能,Delphi 程序员不会经常用到它。因为后面章节要讨论相关的内容(尤其是“方法指针” Delphi用得特别多),这里不妨先了解一下。如果你是初学者,可以先跳过这部分,当学到一定程度后再回过头阅读这部分。Pascal 中的过程类型与C语言中的函数指针相似。过程类型的声明只需要参数列表;如果是函数,再加个返回值。例如声明一个过程类型,该类型带一个通过引用传递的整型参数:type IntProc = procedure (var

26、Num: Integer);这个过程类型与任何参数完全相同的例程兼容(或用C语言行话来说,具有相同的函数特征)。下面是一个兼容例程:procedure DoubleTheValue (var Value: Integer);begin Value := Value * 2;end;注意:在16位Delphi中,如果要将例程用作过程类型的实际值,必须用far指令声明该例程。过程类型能用于两种不同的目的:声明过程类型的变量;或者把过程类型(也就是函数指针)作为参数传递给另一例程。利用上面给定的类型和过程声明,你可以写出下面的代码:var IP: IntProc; X: Integer;begin

27、IP := DoubleTheValue; X := 5; IP (X);end;这段代码与下列代码等效:var X: Integer;begin X := 5; DoubleTheValue (X);end;上面第一段代码明显要复杂一些,那么我们为什么要用它呢?因为在某些情况下,调用什么样的函数需要在实际中决定,此时程序类型就很有用。这里不可能建立一个复杂的例子来说明这个问题,不过可以探究一下简单点的例子,该例名为ProcType。该例比前面所举的例子都复杂,更接近实际应用。如图6.3所示,新建一个工程,在上面放两个radio按钮和一个push按钮。例中有两个过程,一个过程使参数的值加倍,与

28、前面的DoubleTheValue过程相似;另一个过程使参数的值变成三倍,因此命名为TripleTheValue图 6.3: 例 ProcType 窗体 procedure TripleTheValue (var Value: Integer);begin Value := Value * 3; ShowMessage (Value tripled: + IntToStr (Value);end;两个过程都有结果显示,让我们知道他们已被调用。这是一个简单的程序调试技巧,你可以用它来检测某一代码段是否或何时被执行,而不用在代码中加断点。当用户按Apply 按钮,程序会根据radio按钮状态选择执

29、行的过程。实际上,当窗体中有两个radio按钮时,你只能选择一个,因此你只需要在Apply 按钮的OnClick 事件中添加代码检测radio按钮的值,就能实现程序要求。不过为了演示过程类型的使用,我舍近求远选择了麻烦但有趣的方法:只要用户选中其中一个radio按钮,按钮对应的过程就会存入过程变量:procedure TForm1.DoubleRadioButtonClick(Sender: TObject);begin IP := DoubleTheValue;end;当用户按Apply 按钮,程序就执行过程变量保存的过程:procedure TForm1.ApplyButtonClick(

30、Sender: TObject);begin IP (X);end;为了使三个不同的函数能访问IP和 X变量,需要使变量在整个窗体单元中可见,因此不能声明为局部变量(在一个方法中声明)。一个解决办法是,把这些变量放在窗体声明中:type TForm1 = class(TForm) . private Private declarations IP: IntProc; X: Integer; end;学完下一章,你会更清楚地了解这段代码的意思,目前只要能知道怎样添加过程类型定义、怎样修改相应的代码就行了。为了用适当的值初始化上面代码中的两个变量,你可以调用窗体的OnCreate 事件(激活窗体后

31、,在Object Inspector中选择这一事件,或者双击窗体)。此外最好仔细看一看上例完整的源代码。在第九章的 Windows 回调函数一节,你能看到使用过程类型的实例函数重载 重载的思想很简单:编译器允许你用同一名字定义多个函数或过程,只要它们所带的参数不同。实际上,编译器是通过检测参数来确定需要调用的例程。下面是从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): Do

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1