子程序及其实现方式

上传人:人*** 文档编号:513981797 上传时间:2023-03-14 格式:DOC 页数:7 大小:34.02KB
返回 下载 相关 举报
子程序及其实现方式_第1页
第1页 / 共7页
子程序及其实现方式_第2页
第2页 / 共7页
子程序及其实现方式_第3页
第3页 / 共7页
子程序及其实现方式_第4页
第4页 / 共7页
子程序及其实现方式_第5页
第5页 / 共7页
点击查看更多>>
资源描述

《子程序及其实现方式》由会员分享,可在线阅读,更多相关《子程序及其实现方式(7页珍藏版)》请在金锄头文库上搜索。

1、子程序及其实现方式引言随着程序设计语言的逐步发展,代码的规模越来越大。不管是在传统的面向过程的,还是随后的面向数据的,乃至现在的面向对象的程序设计中,过程抽象和数据抽象在提高代码的可读性、复用性方面起着重要的作用,因此是解决程序设计复杂性的利器。子程序就是过程抽象的一个方式。子程序的主要作用是对某个子功能具体的实现细节进行封装。利用子程序,我们可以有效的使主程序从复杂的各种实现中抽象出来,使得整体的思路更加的清晰。我们还可以对多出重复出现的相同功能的代码段进行封装,提高代码的复用性。一、 子程序的基本概念1.1函数与过程过程:过程实际上是一个语句序列,在这个序列中可以访问非局部变量,以及通过在

2、建立在形参和实参之间的单向或者双向通道来进行对调用程序的变量的值的修改。函数:函数在语义上是数学函数的模拟,通常情况下函数没有因为别名等而产生的副作用。也就是说函数只是通过返回值对调用程序产生影响。在大多数的程序设计语言中提供了函数和过程,但是在C和C+中只有函数。但是这个函数和上面定义的函数不是严格的一样,倒是和过程很类似。1.2程序名、实参、形参在程序设计语言中,在进行子程序调用之前必须对子程序进行声明和定义。在C+中声明和定义可以是分开的,但是在java中两者同时进行。程序的声明包括告诉编译器子程序的名称、以及参数。在子程序头出现的参数称为形参。在调用程序中向子程序传递的与形参对应的参数

3、称为实参。1.3子程序设计中的几个常见问题首先最明显的一个问题是子程序对与非局部变量的访问方式,是采用静态作用于还是动态作用域。其次,参数传递的实现方式多种多样,具体选择哪种实现。再其次,子程序的局部环境的性质,最主要的是局部变量是栈动态的还是静态的。如果是静态的就不能进行递归调用。最后是子程序的重载和通用子程序的问题。二、 子程序的局部引用环境在子程序中也可以变量定义,在子程序中定义的变量叫做局部变量。局部变量的实现可以是栈动态的也可以是静态的。2.1栈动态如果局部变量是栈动态的,意味着在子程序被调用之前这些变量并没有被绑定到内存空间。具体的绑定发生在子程序开始执行时,然后在子程序终止执行时

4、解除绑定。栈动态变量的优点有下面几个方面:I.子程序的灵活性更高,例如可以进行递归调用。II.局部变量的存储空间可以被共享。在早期内存空间相对较小时这点很重要。但是在现代大容量内存的环境下已不是很明显。栈动态的主要缺点是:I.在每次调用的时候都要进行存储空间的分配和绑定,结束时都要进行空间的释放。这一个过程是一个很大的开销。II通过栈动态实现的变量被放置与栈中,具体的地址只有在运行时才能确定。因此对栈变量的访问是一个间接寻址的过程,而对静态变量的访问可以通过直接寻址实现。通常情况下,间接寻址的代价比直接寻址的要高。2.2静态静态方式指的是在程序被加载和链接之后,变量就已经被绑定到存储空间。与栈

5、动态相比最大的优点是效率比较高。原因是静态的没有动态的一个内存分配和释放的代价,同时更是直接寻址。在C和C+除非变量被static修饰的是静态变量,否则都是栈动态的。Pascal、Ada和Java只有栈动态的方式。FORTRAN 90中用户可以自己选择是栈动态还是静态。三、 参数传递的方法3.1参数传递的语义模型参数传递方式指的是参数被传递到子程序,或者从子程序获取的方式。参数传递从语义上讲将有三种模型:输入性、输出型和输入输出型。输入型指的是形参可以接受对应的实参的数据。输出型指的是形参的数据可以传送到相应的实参。输入输出型指的是两者的功能的结合。3.1.1输入型的实现3.1.1.1按值传递

6、按值传递指的是用对应的实参的值对形参进行初始化。想要实现按值传递的语义,我们一般有两种实现的方式:实际数据的传递 ,这种情况下形参和局部变量一样需要被绑定到额外的存储空间。然后将实参的值拷贝到新分配的存储空间。因此在实参数据比较大的情况下比如一个较大的数组,这种拷贝的代价比较高。传递一条通往调用程序中实参的路径,这种传递方式不需要分配额外的空间给形参,一般只是保存实参的一个地址。但是在输入型语义的要求下,该形参必须是写保护的。否则可能会造成变量别名的副作用。3.1.2输出型的实现3.按结果传递按结果传递实现的是输出型语义。在这种情况下,在子程序开始执行时,实参的值并不传递给形参。但是在子程序终

7、止时形参的值必须传递给实参。与按值传递一样我们也有相同的两种实现:实际数据传递和通过传递存储路径。实际数据传递遇到的问题和按值传递相同,需要额外的存储空间。3.1.3输入输出的实现3.1.3.1按值与结果传递在按值与结果传递中实现的方式一般是将实际值进行传递。形参具有额外分配的空间。在子程序被调用时将实参的值按输入型的方式传递给形参。在子程序终止时,按输出型的方式将值从形参传递给实参。这种方式有两次复制过程,在实参数据所占的存储空间较大时将有花费很高的代价进行值的拷贝。3.1.3.2按引用传递按引用传递指的是在形参和实参之间建立一个存取的路径,一般情况下可以是实参的地址。在子程序中可以对实参进

8、行更改。实际上相当于子程序也拥有实参。按引用传递的优点是不需要额外的空间,也不需要在形参和实参之间进行拷贝,因此效率比较高。按引用传递的缺点主要是容易产生别名。例如子程序声明如下:Int Add(int* a,int*b)调用如下:Add(&a,&a);这样a和b就是别名3.2主要几种现代程序设计语言的参数传递的实现方式 C和C+语言的参数传递方式C语言采用按值传递的方式。对于输入型语义按值传递当然可以满足,同理输出型语义也可以满足。但是对于输入输出型的语义如何实现呢?在C中通过将地址值(指针)作为数据采用按值传递来实现在调用程序和被调用程序之间建立一个存储路径。从而实现输入输出型语义。如过将

9、指针定义为指向常量的指针,这样在子程序中不能对形参进行修改。因此这种情况下实现了输入型语义,同时具有按引用传递的效率。例如:int Add(const int* a,const int *b)C+中还有一种引用类型,但是在C+中这种引用其实是一种特殊的指针。该引用类型通常被隐式的间接引用。这种引用类型通常作为形参来使用,用引用类型来传递参数在本质上并不需要对变量的右值进行拷贝,在子程序调用时,编译器将实参的地址传递给形参。通过这种隐式的间接访问一方面可以实现按引用传递的高效率,同时由于不需要进行显示的间接访问,对引用变量的访问和对实参一样,因此提高了代码的可读性。3.2.2 Java中的参数传

10、递所有的Java参数都是按值传递的,由于java中只有几种基本类型(布尔、数值和字符串)不是对象,其他的所有类型都是对象,并且java中的对象都是显示堆动态的。即都用new操作符进行对象显示分配,但是没有显示的解除分配操作。同时对象都通过引用来进行访问,每个对象在运行时维护一个引用技术。内存的管理有垃圾回收器实现。因此java中对于对象引用的按值传递实际上传递的是引用类型。因此java中对于对象类型的按值传递实际上实现的是按引用传递的输入输出语义。3.4子程序名作为参数进行传递四、子程序的重载及通用性 4.1重载子程序一个子程序的子程序名和参数列表构成了一个协议,重载子程序指的是子程序名相同,

11、但是必须使每一个子程序具有不同的协议,也就是说子程序的参数列表必须不同。操作符重载也是一种子程序重载,只不过子程序名是操作符。4.2通用子程序 为了提高软件的复用性,对于处理不同类型的相同功能的子程序我们可以设计一种编写通用子程序的方式。多数的现代程序设计语言采用编译时参数多态的方式。例如在Ada和C+中在编译时必须为每一个不同的类型创建一个函数的副本,子程序的调用采用静态绑定的方式。但是在有些程序设计语言中只需要保存一个通用的副本,在运行时进行动态的绑定。4.3面向对象中的重载和通用性在面向对象的抽象数据类型中的方法的重载和通用型和传统过程式程序设计中的用法大体相同。特别是通用性对于面向对象

12、程序设计中提高代码复用性有很重要的作用。下面引入一个智能指针的例子来对普通子程序重载、操作符重载和模板类型进行详细说明。c+中堆变量的申请和释放完全由程序员自己控制,这种情况下很容易造成指针悬挂和内存泄露等问题。而Java的内存控制采用引用计数的方式由解释器管理对象。空间的释放垃圾收集器进行管理。但是由于c+一直考虑效率的问题。至今没有引入有效的自动内存管理。因此很多人自己设计了一些自动管理内存对象的模块。典型的是智能指针。尽管不同的人编写的版本具体细节不同,但是大体和com里面的引用计数技术相同。一般智能指针分为内嵌式和分离式。下面具体讨论分离式的实现方式。template/模板类class

13、 smart_ptr private: int *refcount; /对于每一个堆对象维护一个引用计数 T* realptr; /指向堆对象的指针public:/不带参数的构造函数 smart_ptr() /带有参数的构造函数 smart_ptr(T* xrealptr) refcount=new int(); *refcount=1; realptr=xrealptr; /拷贝构造函数 smart_ptr(smart_ptr& src) this-refcount=src.refcount; this-realptr=src.realptr; AddRef(); /赋值操作,=运算符重载

14、smart_ptr& operator =(smart_ptr& src) if(realptr=src.realptr) return *this; Release(); this-refcount=src.refcount; this-realptr=src.realptr; AddRef(); /-运算符重载 T* operator -() return realptr; void AddRef() *refcount=*refcount+1; void Release() if(*refcount0) *refcount=*refcount-1; if(*refcount=0) ShowMessage(释放对象)

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 高等教育 > 其它相关文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号