第六章过程2020/2/212内容提要引言函数(Function)过程子程序(Sub)过程参数的传递变量与过程的作用域Shell函数的应用2020/2/213引言引言使用“过程”是实现模块化程序设计思想的重要方法。模块化程序设计思想的要点之一是对一个复杂问题采用“分而治之”的策略----模块化,即把一个较大的程序划分为若干个模块,每个模块只完成一个或几个功能。这些模块通过执行一系列的语句来完成一个特定的操作过程,因此被称为“过程”。模块化程序设计的两大优点:容易调试和维护提高了代码的利用率模块化程序设计2020/2/214引言在VB中有两类过程:由系统提供的内部函数过程和事件过程事件过程是VB应用程序的主体。由用户自定义的通用过程通用过程用来完成一项指定的任务,它不与任何事件相联系,只能由别的过程来调用,可以存储在窗体或标准模块中。通用过程分为两种:(1)子程序过程:以Sub保留字开始的过程;(2)函数过程:以Function保留字开始的过程。模块化程序设计2020/2/215编写一个通用的函数过程,使其可以求任意整形数的阶乘,即n!,并利用这个函数过程解决5!+6!+7!的问题。例6-1引言2020/2/216将例6-1改用子程序过程求解。例6-2引言2020/2/217引言利用通用过程解决问题分两步走:定义过程用户确定过程种类和名称,编写代码。调用过程由其他过程调用,达到使用自定义过程的目的。过程的定义与调用调用过程执行被调用过继续执行原程序程2020/2/218函数(Function)过程函数过程[Static][Public|Private]Function函数过程名([参数列表])[As类型]语句块[ExitFunction]函数名=返回值语句块EndFunction函数过程的定义定义格式2020/2/219说明:(1)函数过程名的命名规则同变量名。(2)参数列表(形参)形式:[ByVal][ByRef]变量名或数组名[As类型]参数列表类似于变量声明,它指明了从调用过程传递给被调用过程的参数(变量)个数和类型,各参数之间用逗号分隔。(3)As类型:函数返回值的类型。(4)函数名=返回值:在函数体内至少对函数名赋值一次。若不赋值,则默认返回值为0。(5)函数过程不能嵌套定义,但可以嵌套调用。函数过程2020/2/2110定义方法函数过程有两种定义方法:(1)利用“工具”菜单下的“添加过程”命令定义,生成一个函数过程的框架。(2)利用代码窗口手工输入。函数过程2020/2/2111函数过程常用形式:变量名=函数过程名(实参列表)或print函数过程名(实参列表)说明:(1)实参是在调用过程时传递给过程的常量、变量、表达式或数组。实参的个数、类型、顺序应与相应的形参保持一致。(2)函数过程的调用只能出现在表达式中,不能作为单独的语句。函数过程的调用2020/2/2112编写一个函数过程,统计一串字符中某个字符的出现次数,并在事件过程中调用它,以得到结果。例6-3函数过程2020/2/2113子程序(Sub)过程子程序过程[Static][Public|Private]Sub子程序过程名([参数列表])语句块[ExitSub]语句块EndSub子程序过程的定义定义格式2020/2/2114说明:(1)子过程名、参数列表、语句块等与函数过程的要求基本相同。(2)在子过程中如果没有形参,调用时括号()必须省略。(3)子过程也不能嵌套定义,但可以嵌套调用。定义方法与函数过程的定义方法相同。子程序过程2020/2/2115格式:Call过程名(实参列表)或过程名实参列表说明:(1)实参的个数、类型、顺序应与相应的形参保持一致,子过程中如果没有形参,则调用中也无实参。(2)子过程的调用是作为一条独立语句出现的。子程序过程的调用子程序过程2020/2/2116(1)函数名是一个变量,它有值,有类型,在函数体中至少赋值一次,并通过它可带回一个结果;而Sub过程名无值,无类型,在Sub过程体内不能赋值,不能通过它带回结果。(2)调用时,子过程调用是一句独立的语句。函数过程不能作为单独的语句加以调用,必须参与表达式运算。注意:Sub过程若要带回结果,必须通过形参与实参的传递得到结果,调用时可得到多个参数值。函数过程与Sub过程的区别子程序过程2020/2/2117编写两个Sub子过程,Sub子过程daying1,打印一行“-”信息,Sub子过程daying2,打印两个“|”,这两个Sub子过程不需要参数,因此参数表为空,在窗体单击事件过程中,分别调用这两个子过程,以打印一个图形。例6-4子程序过程2020/2/2118将例6-3的例子改为用一个子过程实现。例6-5子程序过程2020/2/2119将例6-2的例子改为用一个子过程实现。例6-6子程序过程2020/2/2120参数的传递参数的传递过程与外界的数据通信:调用过程的目的就是在一定条件下完成某项工作。外界要把条件告诉过程,或者反过来,过程要把处理结果报告给外界。数据通信的两种方式:(1)在过程内部使用全局变量。由于这种变量在过程内、外都能使用,实际就是直接处理外界的变量。(2)参数传递。调用过程时可以把数据传递给过程,也可以把过程中的数据传递回来。在调用过程时要考虑调用过程(主调过程)和被调用过程之间的数据如何传递。使用过程的关键问题是正确地提供过程的传入数据和正确地引用其传出数据。2020/2/2121参数的传递过程的形参与实参:形参是指在定义通用过程时,出现在Sub或Function语句中的变量名(数组名)。形参用于接收过程中要使用的数据。实参是指在调用Sub或Function过程时,传递给过程的、有确定值的常量、变量或表达式。在调用过程时,调用过程中使用的是实际参数,它要与定义过程时(被调用过程)的形式参数一一对应,并以适当的形式将实参传给形参,这便是参数传递,也称为虚(形参)实(实参)结合。实参列表与形参列表中的参数要一一对应,个数必须相等,变量可以同名,也可以不同名,类型要相符。2020/2/2122参数的传递形参与实参的对应关系:实参调用过程:Calltest(9,a,b())定义过程:Subtest(xAsByte,yAsSingle,z()AsLong)(被调用过程)形参参数传递的方式:值传递:将实参的值传给形参。地址传递(默认方式,也叫引用):将实参的地址传给形参,形参与对应实参使用相同的内存地址。2020/2/2123参数的传递如果调用语句中的实参是常量或表达式,或者定义过程时选用ByVal关键字,就是按值传递。按值传递参数时,系统将实参的值复制给形参,实参与形参便断开了联系,被调用过程中的操作是在形参自己的存储单元中进行的(即使实参变量与形参变量名称相同,在内存中也占据不同的存储单元),当过程调用结束时,这些形参所占用的存储单元也同时被释放。因此在过程中对形参的任何操作不会影响到实参。采用按值传递只能从外界向过程传入数据,但不能传出,即数据通信是单向的,正因为如此,形参的值就不会影响外界的任何量,因而比较安全。值传递2020/2/2124验证实例一。例6-7参数的传递2020/2/2125参数的传递如果调用语句中的实参是变量(或数组),或者定义过程时选用ByRef关键字,就是按地址传递。按地址传递参数时,系统将实参的地址传给形参,即形参和实参使用相同的存储单元,因此在被调用过程中对形参的任何操作都变成了对相应实参的操作,因此实参的值就会随形参的改变而改变。采用按地址传递既能传入数据,也能传出,即数据通信是双向的。按值传递和按地址传递参数各有特点,一般来说,需要传出数据时应该用按地址传递,否则采用按值传递为好。地址传递2020/2/2126验证实例二。修改例6-7中的程序,将子过程的参数前说明传递方式的关键字byval删除。例6-8参数的传递2020/2/2127参数的传递可以将数组或数组元素作为参数进行传递。用数组名作为形参或实参时,相当于地址传递方式,即将实参数组的起始地址传给形参数组的起始地址,实参数组和形参数组共享一片地址连续的存储单元。在被调用过程中不可再用Dim语句定义所要传递的数组。如果要传递数组中的某一元素,则在调用语句中直接写上该数组元素,如,CallTest(5,a(3))在形参列表中说明数组时,无需说明其维数,但圆括号不能省略(实参列表中的圆括号可省略)。数组的传递2020/2/2128求数组中元素的最大值。例6-9参数的传递2020/2/2129数组的排序问题。例6-10参数的传递2020/2/2130变量与过程的作用域变量与过程的作用域在建立VB应用程序时,应首先设计代码的结构。VB应用程序的结构通常如图所示:应用程序(.vbp)文件至少有一个或若干个窗体模块(.frm)文件其它模块如类模块(.cls)文件等可以有一个或若干个标准模块(.bas)文件事件过程(sub)子过程(sub)函数过程(function)子过程(sub)函数过程(function)自定义属性过程自定义方法过程自定义事件过程2020/2/2131过程的作用域分为两级:模块级(文件级):只能在本模块或本文件中被调用。这类过程定义时在Sub或Function之前加上Private关键字。全局级(工程级):在整个工程内均能被调用。这类过程定义时在Sub或Function之前加上Public关键字(或什么也不加,系统默认为全局级)。过程的作用域变量与过程的作用域2020/2/2132设计两个窗体,编写两段程序代码,验证全局级过程与窗体级过程的不同。例6-11变量与过程的作用域2020/2/2133不同作用范围的过程定义及调用规则变量与过程的作用域窗体标准模块作用范围模块级全局级窗体标准模块定义方式过程名前加Private过程名前加Public或缺省能否被本模块调用能能能能能否被其它模块调用不能不能能,但必须在过程名前加窗体名能,但过程名必须唯一,否则要加标准模块名2020/2/2134变量的作用域分为三级:过程级(局部变量):指在过程内部定义,只能在过程内使用的变量。定义方式:Dim,Static。局部变量随过程的调用而分配存储单元,一旦该过程结束,变量的内容自动消失,占用的存储单元被释放。窗体/模块级:指在窗体/模块文件之内,在所有过程之外定义的变量。定义方式:在“通用声明”段中用Dim或Private声明。该变量可被本窗体/模块的任何过程访问,但不能被其他模块文件中的过程访问。全局级(工程级)(全局变量):指只能在标准模块的任何过程外,即在“通用声明”段中用Public声明的变量,可被应用程序的任何过程访问。全局变量的值在整个应用程序中始终不会消失和重新初始化,只有当整个应用程序执行结束时才会消失。变量的作用域变量与过程的作用域2020/2/2135不同作用范围的变量声明及使用规则变量与过程的作用域作用范围局部变量窗体/模块级变量全局变量窗体标准模块声明方式Dim,StaticDim,PrivatePublic声明位置过程中窗体/模块“通用声明”段标准模块的“通用声明”段能否被本模块其他过程访问不能能能能否被其它模块访问不能不能能,但须在过程名前加窗体名能2020/2/2136模块级变量与局部变量应用实例。例6-12变量与过程的作用域2020/2/2137结论:在同一模块不同过程中定义的变量可以同名。这些变量占用不同的存储单元,互不相干。在同一模块不同级别中定义的变量可以同名。此时,系统优先访问作用域小的变量名,作用域大的变量被“屏蔽”。也就是说,在过程中直接引用的变量是同名变量中作用域最小的那个变量。若想访问作用域大的变量,则必须在作用域大的变量名前加模块名。在不同模块中定义的全局变量可以同名。如果在窗体模块的“通用声明”段用Public关键字定义全局变量,则该变量的作用域仅限于窗体模块,只有在标准模块的“通用声明”段用Public关键字定义的全局变量,其作用域才是整个应用程序。变量与过程的作用域2020/