第5章过程和函数.docx
- 文档编号:4166732
- 上传时间:2022-11-28
- 格式:DOCX
- 页数:77
- 大小:393.08KB
第5章过程和函数.docx
《第5章过程和函数.docx》由会员分享,可在线阅读,更多相关《第5章过程和函数.docx(77页珍藏版)》请在冰豆网上搜索。
第5章过程和函数
第五章过程和函数
对于复杂的程序,结构化程序设计就是对一个复杂的问题采用“分而治之”的策略——模块化,把一个较大的程序划分成若干个模块,每个模块只完成一个或者若干个功能。
VB也是如此,VisualBasic把程序按功能分为多个模块。
每个模块的代码中又分为相互独立的过程,每个过程完成一个具体特定的任务。
使用“过程”不仅是实现结构化程序设计思想的重要方法,而且是避免代码重复,便于程序调试维护的一个重要手段。
在VisualBasic中就是使用子过程或函数过程来构建应用程序。
5.1VB应用程序结构
在建立VB应用程序时,应先设计代码的结构。
VB应用程序的结构通常如图5-1所示。
图5-1VB应用程序结构图
VB将代码存储在3类不同的模块中:
窗体模块,标准模块和类模块,如图5-2所示。
在这3类模块中都可以包含常量和变量的声明以及Sub、Function过程。
它们形成了工程的一种模块层次结构,可以较好地组织工程,同时也便于代码的维护。
通过VB环境的工程资源管理器窗口可以清楚地看到一个工程中的模块层次结构。
详见1.3中图1-9。
图5-2工程中的模块
5.1.1窗体模块
每个窗体对应一个窗体模块,窗体模块包含窗体及其控件的属性设置、窗体变量的说明、事件过程、窗体内的通用过程、外部过程的窗体级声明。
窗体模块保存在以.frm为扩展名的文件中。
默认时应用程序中只有一个窗体,因此有一个以.frm为扩展名的窗体模块文件。
如果应用程序有多个窗体,就会有多个.frm为扩展名的窗体模块文件。
5.1.2标准模块
简单的应用程序通常只有一个窗体,这时所有的代码都放在该窗体模块中。
而当应用程序庞大而复杂时,就需要多个窗体。
在多窗体结构的应用程序中,有些程序员创建的通用过程需要在多个不同的窗体中共用,为了不在每个需要调用该通用过程地窗体重复键入代码,就需要创建标准模块,标准模块包含公共代码的过程。
标准模块保存在扩展名为.bas的文件中,缺省时应用程序不包含标准模块。
标准模块可以包含公有或模块级的变量、常量、类型、外部过程和全局过程的全局声明或模块级声明。
缺省时,标准模块中的代码时公有的,任何窗体或模块的事件过程或通用过程都可以调用它。
在许多不同的应用程序中可以重用标准模块,在标准模块中可以定义通用过程,但不可以定义事件过程。
5.1.3类模块
在VB中,类模块是面向对象编程的基础,文件以.Cls为扩展名。
程序员在类模块中编写代码建立新对象,这些新对象可以包含自定义的属性和方法,可以在应用程序中使用。
类模块与标准模块的不同之处在于标准模块仅仅含有代码,而模块既含有代码又含有数据。
5.1.4VB过程分类
1.子过程
1)事件过程
事件过程由VB自行声明,附加在窗体和控件上,用户不能增加或删除。
当用户对某个对象发出一个动作时,Windows会通知VB产生了一个事件,VB会自动地调用与该事件相关的事件过程。
事件过程只能放在窗体模块中。
事件过程的常用格式如下:
PrivateSub<对象名>_<事件名([<形参表>])>
<语句系列>
EndSub
2)通用过程
通用过程由用户定义或删除修改,可以放在标准模块中,也可以放在窗体模块中,其格式如下:
[Private|Public]Sub<过程名>(<参数表>)
<语句系列>
EndSub
2.函数过程
1)系统函数
VB为了简化程序设计,提供了许多内部函数供设计者调用,如Abs(),Int(),ASC(),MID()等。
常用系统函数的使用在本书的第二章有详细介绍。
2)用户自定义函数
除了有固定功能的系统函数之外,还允许用户编写自己的函数过程,被称为用户自定义函数,格式如下:
[Private|Public]Function<自定义函数过程名>(<参数表>)[As<类型>]
<语句>
EndFunction
5.2子过程SUB的定义和调用
5.2.1创建子过程
建立通用过程有两种方法:
直接在“代码”编辑窗口中输入过程代码或使用“添加过程”对话框。
1.在“代码”编辑窗口中输入
在“代码”编辑窗口中,把光标定位在已有过程的外面(即通用声明段),然后按如下格式输入通用过程:
[Private|Public][Static]Sub<过程名>([<形参表>])
<语句系列>
[ExitSub]
[<语句系列>]
EndSub
说明:
1)Public|Private
可以将子过程放入标准模块、类模块和窗体模块中。
按照缺省规定,所有模块中的子过程为Public(公有的),这样在应用程序中可随处调用它们。
如果选用Private,则只有该过程所在模块中的程序才能调用该过程。
2)Static
若使用Static关键字,则该过程中的所有局部变量的存储空间只分配一次,切这些变量的值在整个程序运行期间都存在,即在每次调用该过程时,各局部变量的值一直存在;若省略Static,过程每次被调用时重新为其变量分配存储空间,当该过程结束时释放其变量的存储空间。
3)过程名
过程名的命名规则与变量名相同,长度不超过40个字符。
一个过程名只能有唯一的名字,在同一模块中,同一名称不能既作Sub过程名又作Function函数过程名。
4)语句系列
是过程的过程体,语句系列中可以用一个或多个ExitSub语句从过程中退出。
5)形参表
形参表中的语法为:
[ByVal]参数名1[As类型名],[ByVal]参数名2[As类型名],…,
其中ByVal表明该参数是值传递方式。
形参表中出现的参数称为形式参数,简称形参。
它并不代表一个实际的存在变量,在调用此过程时,存储对应实参传递过来的确定的值。
类似于变量声明,它指明了从调用过程传递给被调过程变量的个数和类型。
各变量名之间用逗号分隔,其中的形式参数被缺省为具有Variant数据类型,但建议将形参声明一个指定的数据类型。
2.使用“添加过程”对话框
使用“添加过程”对话框建立过程的步骤为:
(1)打开要添加过程的代码编辑窗口。
(2)执行“工具”菜单中的“添加过程”命令,打开“添加过程”对话框,如图5-3所示。
图5-3过程添加对话框
(3)在“名称”文本框中输入过程名。
从“类型”中选择“子程序”类型。
从“范围”组中选择范围,相当于使用Public或Private关键字。
(4)单击“确定”按钮。
使用这个方法建立了一个过程模板,可以在模板上添加过程体代码。
5.2.2调用子过程
SUB过程可以被其它过程(包括事件过程和通用过程)调用。
每次调用过程都会执行Sub和EndSub之间的语句系列。
Sub过程以Sub开始,以EndSub结束。
当程序遇到EndSub时,将退出过程,并立即返回到调用语句的后续语句中。
1.调用方法
调用Sub过程有两种方法:
(1)使用Call语句:
Call<过程名>([<实参表>])
(2)直接使用过程名:
<过程名>([<实参表>])
2.使用说明
(1)<实参表>是实际参数表,实参必须用圆括号括起,参数与参数之间用逗号分隔。
(2)当用Call语句调用执行过程时,若无实参,其过程名后圆括号不能省略,若有参数,则参数必须放在括号之内。
(3)若省略Call关键字,则过程名后不能加括号,若有参数,则参数直接跟在过程名之后,参数与过程名之间用空格分隔,参数与参数之间用逗号分隔。
例如,以下两个语句都调用Recarea过程:
CallRecarea(6,7)
Recarea6,7
3.实例应用
【例5.1】编写一个计算矩形面积的Sub过程,然后调用该过程计算矩形面积。
PrivateSubForm_Click()
DimAAsSingle,BAsSingle
A=Val(InputBox("请输入矩形长度?
"))
B=Val(InputBox("请输入矩形宽度?
"))
CallRecarea(A,B.
EndSub
SubRecarea(RlenAsSingle,RwidAsSingle)
DimAreaAsSingle
Area=Rlen*Rwid
MsgBox"总面积是"&Area'输出矩形面积
EndSub
在以上实例中,子过程Recarea用来计算矩形面积并显示计算结果,主调程序Form_Click提供实际参数A、B,分别为矩形的长和宽。
当执行到主调程序中的语句CallRecarea子过程时,程序流程进入Recarea子过程内部,实际参数A、B分别传递给形式参数Rlen,Rwid,直到遇到EndSub语句才结束Recarea子过程,返回到主调程序Form_Click中。
5.3函数过程的定义和调用
函数过程是过程的另一种形式,当过程的执行需要返回一个值时,使用函数就比较简单。
Function过程和内部函数一样,可以在程序或函数嵌套中使用。
5.3.1创建用户自定义函数过程
与Sub过程一样,Function过程也是一个独立的过程,可读取参数、执行一系列语句并改变其参数的值。
创建用户自定义函数过程有两种方法:
直接在“代码”编辑窗口中输入函数过程代码或使用“添加过程”对话框。
1.在“代码”编辑窗口中输入
在“代码”编辑窗口中,把光标定位在已有过程的外面,然后按如下格式输入函数过程:
[Private|Public][Static]Function<函数过程名>([<形参表>])[As<类型>]
<语句系列>
[<函数名>=<表达式>]
[ExitFunction]
[<语句系列>]
[<函数名>=<表达式>]
EndFunction
说明:
1)Public|Private
与在子过程一样的作用范围。
2)Static
与在子过程一样的作用。
3)函数过程名
函数过程名的命名规则与变量名相同,长度不超过40个字符,同样,一个过程名只能有唯一的名字在同一模块中,同一名称不能既作Function函数过程名又作Sub过程名。
As<类型>指定Function过程返回值的类型,可以是Integer,Long,Single,Double,Currency,String或Boolean。
如果没有As子句,缺省的类型为Variant。
4)语句系列
是函数的过程体,语句系列中可以用一个或多个ExitFunction语句从函数中退出。
5)形参表
形参表的含义与Sub相同。
6)表达式
表达式的值是函数返回的结果。
在程序中,通过赋值语句将值赋给函数名,该值就是Function过程返回的值。
如果在Function过程中省略了“<函数名>=<表达式>”,则该过程返回一个默认值:
数值函数过程返回0,字符串函数过程返回空字符串。
因此,为了能使一个Function过程完成所指定的操作,通常要在过程中为函数赋值。
2.使用“添加过程”对话框
使用“添加过程”对话框建立过程的步骤与添加子过程步骤一致,只是在“添加过程”对话框中选择类型为“函数”即可。
5.3.2调用函数过程
1.调用方法
函数过程的调用比较简单,可以像使用VB内部函数一样来调用Function过程,只需要在表达式中写上它的名字。
其语法格式如下:
变量=函数名(实参1,实参2,实参3,…,实参n)
显然,与调用子程序的方法不同,自定义函数的调用遵循内部函数(如Sin、Abs、ASC等)的调用规则,实参也必须用圆括号括起来。
2.使用说明
实参可以是常量、变量、表达式或数组变量名。
实参数据的类型应与子程序定义时的形式参数类型一致。
当子程序的形参传送方式是地址传递时,调用时的实参必须是变量,不允许是常量或表达式。
例如:
a=Myfunction(5,10,1)
3.实例应用
【例5.2】求1到6的阶乘之和,即1!
+2!
+…+6!
Functionfact(xAsInteger)AsLong
DimPAsLong,iAsInteger
P=1
Fori=1Tox
P=P*i
Nexti
fact=P
EndFunction
PrivateSubCommand1_Click()
DimsumAsLong,iAsInteger
Fori=1To6
sum=sum+fact(i)
Nexti
Label2.Caption=sum
EndSub
以上实例中的fact函数用来完成x!
的计算,主调程序Command1_Click用语句sum=sum+fact(I)来完成函数fact的调用,将实参I的值传递给形参x,在函数fact中赋值语句fact=P将x!
的值通过函数名返回到主调程序中。
在主调程序的循环体循环6次就完成了1!
,2!
,…,6!
的计算,并进行求总和,将总和在标签Label2中显示。
5.3.3函数过程与子过程的区别
函数过程与子过程的区别如下:
1)适用范围
把某功能函数定义为函数过程或子过程,没有严格的规定,但只要能用函数过程定义的,一定能用子过程定义,反之不一定。
因此子过程比函数过程适用范围广。
但当只需要返回一个值时,习惯用函数过程,当需要返回多个值时,习惯用子过程。
2)返回值
函数过程有返回值,函数过程名也就有类型,同时在函数过程体内必须对函数过程名赋值。
子过程名没有值,子过程名也就没有类型,不能在子过程体内对子过程名赋值。
3.实例应用
【例5.3】VB提供了一个标准函数Replace(),实现查找与替换的功能。
现在分别用用户自定义子过程和函数过程来实现。
PublicFunctionMyReplace(s$,OldS$,NewS$)AsString
Dimi%,lenOldS%
lenOldS=Len(OldS)
i=InStr(s,OldS)
DoWhilei>0
s=Left(s,i-1)+NewS+Mid(s,i+lenOldS)
i=InStr(s,OldS)
Loop
MyReplace=s
EndFunction
PublicSubsMyReplace(s$,OldS$,NewS$)
Dimi%,lenOldS%
lenOldS=Len(OldS)
i=InStr(s,OldS)
DoWhilei>0
s=Left(s,i-1)+NewS+Mid(s,i+lenOldS)
i=InStr(s,OldS)
Loop
EndSub
PrivateSubCommand1_Click()
DimstrAsString
PrintMyReplace(Text1,Text2,Text3)
str=Text1
CallsMyReplace(str,Text2,Text3)
Text1.Text=str
EndSub
在上述Command1_Click中,替换后的值通过函数名返回,而在子过程中只有通过变量str作为数据通道来传递。
特别指出,对象属性不能完成地址方式的传递。
5.4过程调用中的参数传递
调用过程的目的,就是在一定的条件下完成某一工作或计算某一数值。
调用过程时可以把数据传递给过程,也可以把过程中的数据传递回来。
在调用过程中,必须考虑调用过程和被调用过程之间的数据的调用方式。
VB中用参数来实现主调过程和被调过程间的数据传递。
通常在编制一个过程时,要考虑它需要输入哪些量,进行处理后输出哪些量。
正确地提供一个过程的输入数据和正确地引用其输出数据,时使用过程的关键问题,也就是通过调用过程和被调用过程之间的数据传递问题。
5.4.1形式参数与实际参数
1.形式参数
形式参数是接收数据的变量。
形式参数表中的各个变量之间用逗号分隔。
形式参数表中的变量类型可以是合法的简单变量,也可以是数组如A(),但不能是定长字符串。
例如在形参表中只能用如Str1AsString之类的变长字符串作为形式参数,不能用Str1AsString*40之类地定长字符串作为形式参数,但定长字符串可以作为实际参数传递给过程。
2.实际参数
实际参数是指在调用Sub或Function过程时,传递给Sub或Function过程的常量、变量或表达式。
实参表可由常量、表达式、合法的变量名、数组名(后跟左、右括号)组成,实参表中各参数用逗号分隔。
形式参数与实际参数的对应关系用下图5-4所示:
调用过程:
CallSub1(23,A(),"VB6.0",rest)
被调用过程:
SubSub1(aAsInteger,aa()AsSingle,bbAsString,ccAsLong)
图5-4形参与实参的对应关系
在定义过程时,形式参数为实际参数保留位置。
在调用过程时,实际参数被插入对应形式参数变量处,第1个形式参数接收第1个实际参数的值,第2个形式参数接收第2个实际参数的值,依此类推。
如上图5-6中,调用过程提供实际参数23、A()、"VB6.0"、rest,被调子过程Sub1提供形式参数aa、a()、bb、cc。
当执行调用时,实参23传递给a,实参A()传递给aa(),实参"VB6.0"传递给bb,实参rest传递给cc。
在调用时完成形式参数与实际参数的结合,即把实际参数传递给形式参数,然后按形式参数执行被调用的过程。
5.4.2值传递和地址传递
参数传递的方式有两种:
值传递和地址传递。
1.值传递
如果在定义形式参数时使用了ByVal,或者在调用语句中的实际参数是常量或表达式,那么实参与形参之间数据传递方式是值传递。
在调用过程时,当实参是常量时,直接将常量值传递给形参变量中;当实参是变量时,仅仅将实参变量的值传递给形参变量。
然后执行被调过程,在被调过程中,即使对形参发生改变也不会影响实参值的变化。
2.地址传递
按地址传递参数,就是将实参的地址传递给相应的形参,形式参数与实际参数使用相同的内存地址单元,这样通过调用被调程序可以改变实参的值。
在进行地址传递时,实际参数必须是变量,常量或表达式无法进行地址传递。
系统缺省的参数传递方式是按地址传递。
3.实例应用
下面是一个既有值传递又有地址传递的实例。
【例5.4】先对a、b赋一个初值,然后调用子过程P1,因参数的传递方式不同,a、b参数的原值发生了变化。
程序清单如下:
PrivateSubForm_Click()
DimaAsInteger,bAsInteger
a=20:
b=50
p1a,b
Print"a=";a,"b=";b
EndSub
Subp1(xAsInteger,ByValyAsInteger)
x=x*10
y=y+20
EndSub
图5-5两种参数传递方式示意图
该程序实参是a,b,被形参是x、y,其中x是地址传递方式,y是值传递方式。
当单击窗体,调用p1a,b语句后,两种参数调用方式见示意图5-5。
实参a的地址传递给形参x,也就是实参a与形参x共同占用一个内存单元,当对形参x执行语句x=x*10后,a,x的值都变成200。
而实参b仅仅将值传递给形参y,当对形参y执行语句y=y+20后,形参y的值变成70,但b的值仍然是50。
因此单击窗体运行程序后,窗体上显示结果a=200,b=50。
4.实参与形参结合时应注意的问题
1)个数、顺序、类型三一致。
实参表与实参表中变量名不必相同,但两表中的个数必须相同,而且各实际参数的数据类型书写顺序必须与相应形式参数的类型要一致。
2)形参是值传递时,对应实参可以是表达式、常量、数组元素。
3)形参是地址传递时,对应实参只能是简单变量,而且是声明了与形参一致的类型。
4)数组、记录类型、对象做参数时只能是地址传递方式。
5)当实参是对象的属性时,是值传递,即使形参是地址传递方式,也不会改变实参的值,也就是不会改变对象的属性值。
5.4.3使用参数
1.使用可选参数
1)定义可选参数
一个过程在声明时定义了几个形参,则在调用这个过程时就必须使用相同数量的实参数。
VisualBasic允许在形参前面使用Optional关键字把它设为“可选参数”。
Optional关键字可以与ByVal、ByRef关键字同时修饰一个参数。
如果一个过程的某个形参为可选参数,则在调用此过程时可以不提供对应于这个形参的实参。
如果一个过程有多个形参,当它的一个形参设定为可选参数时,这个形参之后所有的形参都应该用Optional关键字定义为可选参数。
2)调用可选参数
调用一个具有多个可选参数的过程时,可以省略它的任意一个或多个可选参数。
如果被省略的不是最后一个参数,它的位置要用逗号保留。
如CallSub1(int1,,int2)表明省略了第二个参数。
若一个可选参数没有被省略,则调用语句的实际参数与非可选参数相同。
未得到实参值的形参在调用时被赋以形参类型的默认值。
【例5.5】下面的事件过程在调用一个具有可选参数的过程时,省略了相应的实参。
PrivateSubCommand1_Click()'省略了第二个参数
Callmysub1("abcd")
EndSub
Submysub1(var1AsString,Optionalvar2AsInteger)'第二个参数可选
Text1.Text=var1
Text2.Text=var2'当前情况下,由于var2没有得到相应实参的值,因此var2在调用时被赋以Integer类型的默认值,即var2的值为0。
EndSub
2.可选参数的缺省值
前面讲过,一个可选参数被省略时,调用时赋给形参的是它的数据类型的默认值。
如果希望在省略一个可选参数时,能够赋给形参一个其他特定的值,就要用到给可选参数设定默认值的方法。
可以在声明过程时,通过给可选参数赋值的方法来设定可选参数的默认值。
当调用此过程时即使未提供相应实参的值,形参也会以它的默认值来运行程序。
例题:
PrivateSubCommand1_Click()'省略了第二个参数
Callmysub1("abcd")
EndSub
Submysub1(var1AsString,Optionalvar2AsInteger=10)'第二个参数可选,设定默认值时要注意,赋值号要放在类型名称的后面。
Text1.Text=var1
Text2.Text=var2'此时将var2变量的值10赋给Text2.Text
EndSub
5.4.4数组作为参数传递
1.数组传递原则
整个数组可以作为一个实参传递给过程,但是要求过程在声明
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第5章 过程和函数 过程 函数