第三章C+语言导论_第1页
第三章C+语言导论_第2页
第三章C+语言导论_第3页
第三章C+语言导论_第4页
第三章C+语言导论_第5页
已阅读5页,还剩11页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、第三章 C+语言导论1 面向对象的程序设计由于对于面向对象的分析与设计方法与软件工程早期推出的分析与设计方法存在本质的差别,因此,从二十世纪八十年代中期便陆续出现了支持面向对象的分析与设计方法的高级语言及其开发工具系统。著名的有C+、JAVA、SmallTalk、Delphi等。本章则将围绕最重要C+语言展开论述。C+语言源于C语言的摇篮著名的贝尔(BELL)实验室。二十世纪八十年代初美国AT&T贝尔(BELL)实验室的Bjarne.Stroustrup博士开发出了第一个C+语言编译器。最初的研究成果主要是用于小型计算机系统。直至一九八八年才出现了第一个用于PC的ZORTECH C+ 2.0编

2、译系统,次年出现了TURBO C+ 2.0编译器。紧跟着BorLand公司从1991年起陆续推出了Borland C+ 2.0/3.0/4.0系统。相比之下Microsoft的动作迟缓了一些,直到1992年才推出了基于DOS平台的MSC/C+ 7.0系统。但由于其把握着PC操作系统的命脉,所以发展势头强劲,很快于93年推出了面向Windows的Visual C+ 1.0系统,94年推出了Visual C+ 1.5和可用于Windows95和Windows NT系统平台的Visual C+ 2.0直至98年推出Visual C+ 6.0。 C+语言是在基于C语言的语法基础上容入了Simula67

3、、Algol68和Ada等语言中许多独特的语法特点之后而形成的全新的语言体系。但由于C+语言的语法结构与C语言的语法结构几乎一致且多数编译器供应商所提供的编译器即可编译C语言,同时也可编译C+语言而且还允许这两种语言混编,因而在很大程度上使许多读者误以为C+语言是C语言的改进型语言。另外在事实上,C+语言也的确可以沿用C语言所支持传统的面向过程的分析和设计方法编制出过程化的程序,从而使更多的人对其产生了上面的误解。正是由于这些问题的存在,那些打算自学C+语言的读者便面临着更大的误入歧途的可能性。至于将C+语言和C语言容入一个编译器来进行编译处理主要还是由于存在商业上需求的缘故。正是由于C+语言

4、的语法是基于C语言并考虑到大多数学习C+语言的读者应当系统的修过传统的软件工程所述的面向过程的分析与设计方法和C语言程序设计等课程,所以本书是以此为起点来讲述C+语言的。其更多的篇幅是用在同C语言进行比较的基础上来论述C+语言的语法的。此点务请读者留意。2C+语言新增的约定、符号名称和算符2.1C+语言的文件扩展名 为了使编译器能够区别是C语言还是C+语言,C+语言体系规定用“CPP”(意即C Plus-Plus)做为C+语言源文件的扩展名以区别于C语言用的“.C”文件扩展名。虽然仅差两个字母,但编译时的处理却相差甚远。后面将不再重复C语言已有的内容,所以凡是讲到的多属于C+语言特有的语法描述

5、的内容则只能书写在以“CPP ”为扩展名的文件中(即按C+语法处理)。反过来按C语言语法书写的程序却大多可以使用“CPP”的文件扩展名并用C+编译器处理。但是也有个别易发生一些不符合预期要求的问题(如将在后面讲的重载)。所以为了避免混乱,建议还是按各自语法规则书写。“CPP”的文件扩展名与操作系统无关。与C+语言源文件相关的头文件扩展名一般仍用“H”,但有些操作系统也有规定使用“HPP”充当头文件扩展名的。2.2C+语言最常用的简化输入输出手段在C语言中,输入输出本是依靠函数来实现的(如标准入出用的scanf 、printf等)。通常只要在程序的最前端放置对应的头文件声明“#include”就

6、可以引用这类函数。由于此种函数的引用语句书写起来比较冗长,为了简化起见C+语言又另外定义了一套保留字与算符来替代C语言中对标准入、出函数的引用。C+语言的保留字为:cout“输出内容”“输入内容”; /*为标准输入算符(默认为键盘)*/支持此二算符的内部函数体在一个名为“iostream.h”(即标准I/O流)的头文件中予以声明,所以应用时一定要将其放置对应的头文件声明部位。例1:#includevoid main() char name10; int age; coutname; coutage; cout”name is ”name”n”; cout”age is “age”n”;将例1的

7、标准入出语法与C语言的printf和scanf函数的书写语法对比后可以很明显的看出此种标准的输入、输出语法的书写大大简化了函数格式的描述,而由C+语言编译器按被操作数的类型和具体内容代为选定默认格式。实际上此种方法也有其一整套控制格式的手段。这将是第五章要涉及的内容。2.3数据类型声明的变化一数据类型声明的变化C+语言除了新增的类数据(即class,应用参见第五章)类型以外,继承了C语言所支持的所有数据类型。但在数据类型的声明上作了两种较大的改变,一是允许数据类型的声明语句可以出现在程序的任何位置;二是允许直接使用结构体名定义实体。例2:void main() struct Dtunsigne

8、d int mm,dd,yy; Dt dt3; for(int i=0;i3;i+) dti.mm=8; dti.yy=1994; dti.dd=i+15; 二行注释符/的使用在C语言中用“/*/”符号做程序注释。这种注释叫做段注释。当只做单行注释时便可用连续的两个“/” 符号表示从此符号起至行尾均为行注释内容。这种注释原在C语言中就有效,但一直未公开发表。三用#define预定义代名符在C+语言编程设计中常利用#define语句定义一类空的字符串代换技术被称为代名符定义。代名符在程序中不起任何实际作用,但只能放在行首用来说明程序的设计者、类的归属、 设计时间、程序的分类或所处的总体位置等有助

9、于读程序的信息。例3:#define TESTTEST void main()2.4动态内存分配算符 与上面现象相似的另一类新算符是可以用来进行动态内存分配的。这种算符有两个:new和delete。这是一对真正的算符,无须任何函数支持(即由C+语言编译器直接处理)。C+语言之所以要以new和delete算符来代替C语言内繁多的内存动态分配函数,是由于在面向对象的程序运行中,对象的产生和撤消极其频繁,以至于用C语言内动态内存分配函数来完成这种内存的占用和释放不仅过于烦琐,甚至是不可能的。一算符new的功能与格式 new算符的功能等效于C语言中mal1oc一类的函数功能,被用来动态地为对象或数据分

10、配内存。即在尚未占用的内存空间中为对应类型的数据的实际需要来安排空间,并带回分配的首址。其语法格式为: 指向对应类型的指针=new 类型描述符;类型描述符可有下面几种书写形式:仅占一个单元空间:例4: int *p; p=new int; /*意即占一个机器字长*/仅占一个单元空间且赋初值:例5: int *p; p=new int(20); /*意即占一个机器字长且赋予初值20*/占用多个单元可按数组或指针使用:例6: int *p; p=new int 20; /*意即占20个机器字长单元*/二算符delete的功能与格式 delete算符的功能等效于C语言中的free一类的函数功能。其语

11、法格式为: delete 指针名;如果指针是数组还可在指针名前加上“”表示。即: delete n指针名; 若n值小于定义时的指针单元数,则释放自n单元起的内存空间,但经试验发现实际释放的内存空间仍是全部数组所占用的内存。例7:#include#includevoid main() unsigned int *a,*b; struct dtunsigned int mm,dd,yy; a=new unsigned int(20); /*使a指向一个机器字长的地址单元并赋初值20,*/ /*即等效于a=new unsigned int; *a=20;*/ b=new unsigned int20

12、; /*使b指向20个机器字长的数组单元的第一个*/ for(int i=0;i20;i+)bi=i;/*为这20数组单元赋初值019*/ cout*a b0 b19yy=1994;c-mm=8;c-dd=15; coutyy.mm.dd”n”; printf(“%Np,%Np,%Npn”,a,b,c);/*显示a、b、c的地址值*/ delete a;delete b; a=new unsigned int300; dt *d=new dt; *d=*c;/*将c的内容复制到d内*/ coutyy.mm.dd”n”; printf(“%Np,%Np,%Np,%Npn”,a,b,c,d); /

13、*显示a、b、c、d的地址值*/显示结果:20 0 191994.8.15780D30,780CB0,780C701994.8.157709A4,780CB0,780C70,780C30对例6做如下说明:例中的地址为字长32位的机器运行的随机结果。执行new算符的操作通常按堆栈的存取方式由后向前安排。由于本例运行与保护模式,所分配的内存单元后面还有系统插入的控制编码,且常与系统交叉动态占用内存,因而输出显示的地址植之间是看不出联系的。释放a和b之后,当重新分配a时,由于前一个a指向的是一个字长的空间,不足以容纳第二次要求长达300个单元的分配,只得另辟空间。此种分配便会造成至少一个字长的内存空

14、洞浪费。这种内存空洞被称为内存碎片的一种形态,是C+语言程序在运行时容易造成的一种不良现象。2.5引用(References)类型 这是C+语言的一个特殊的数据类型描述,用于在程序的不同部分使用两个以上的变量名指向同一地址,使得对其中任一个变量的操作实际上都是对同一地址单元进行的。在这种两个以上变量名的关系上,被声明为引用类型的变量名则是实变量名的别名。其语法格式是:类型名 引用型函数名或变量名=前已声明的(常)变量名;在一行上声明多个引用型变量(函数)名时,要在每个变量(函数)名前都冠以“”符号。例8: int i; int &j=i; j=1;例8中的j和i指向同一个地址单元,改变j的值也

15、就是改变了i的值。例9:int i=0;int &j=i,k=2;j+;k+;cout&i”i;cout&j”j;cout&k”234D0-234D4-3例9中地址值以十六进制数显示i的地址。分析时要注意两种不同的“”符号的意义。例中 j是i别名,而 k则是独立的变量。出现在类型声明语句中“”代表符号右端的别名。而在可执行句中“”则是取变量的地址。 此区别千万不能混淆。对于指针使用引用类型时则要注意书写格式。例10:int i=0,*j=&i,*&k=j;cout*k;切不可写成下面的样子:int i,*p;int &r1=p; /*非法语句*/int &r2=&i; /*非法语句*/由于引用

16、类型所声明的变量不是独立内存实体,所以不能用以对常数声明。如:“int &r=3;”的形式就是错误的。 以上为了讲原理,引用类型都被放在同一程序块中。引用类型通常被用于主子函数间需互传大量数据的设计之中,从而减少大量数据经过堆栈的复制。而在C语言中,主、子函数若要对非全局变量实施写操作时,只能通过传递实(形)参的指针 (地址)来实现。直接使用指针很容易造成地址溢出的错误。而用C+语言编制的同类程序中可使用引用类型使得传递的实参、形参都指向同一个内存地址,即减少了大量数据经过堆栈的复制,又避免了地址溢出的错误的发生。这也是C+语言在总结C语言多年编程实践的经验、教训后取得的进展。例11:#inc

17、ludevoid t(int&);void main() int i=0; t(i); cout”i=”i; /*显示*/void t(int &ip)coutip;ip+; /*显示*/例11中函数(子程序) t中的ip被定义为引用类型。把它放在形参位置上与主函数main传来的实参i相对应(指向同一空间等效于传址)。但与用指针传递所不同是ip并非内存实体,是在编译阶段就把这两个符号的地址等同起来,到运行阶段后实际传递的仍是i的地址,只是表象为非地址方式,从而真正体观双方对同一内存地址单元的操作。例11通过这种实、形参在编译阶段建立的别名对应关系确实使得函数t可以直接访问被声明在main中的局

18、部变量i了。2.6const语义的扩展 在C语言中,const保留字是作为声明常数数据类型的附加类别标识使用的,如“const int i=10;”。此时,被声明的常数必须到程序执行后才能被访问。而在C+语言中,则允许被声明的常数在后续的编译中被直接访问。如下面第二句的格式在C+语言中是允许的:例12: const int i=9; char ti; /等效于char 9;/此句在C语言编译时中会报错若在C语言中要实现这种技术,只能借助于“#define i 9”来预定义常数字符代换了。而#define所预定义的常数的类型在编译时是无法确定的。如果用#define预定义的常数做实参传给另一个函

19、数时,该函数只能按声明的形式参数类型来做隐含类型转换了。例13:#include#define k 50void fu n(char);void main() fun(k);void fun(char C)cout”c=”c;执行后显示“c=2”就是将50(0X32)当做ASCII码解释时恰好是“2”的缘故。而能够在编译时直接使用具有明确数据类型常数就不会再发生上面的错误了。2.7指针声明时的类型必须同实际指向的对象类型相一致。在C语言中,指针声明时的类型与其所指向的数据实体的类型可以不一致(借助C语言内定的缺省类型转换技术)。而C+语言则不再允许,这样便大大简化了C+编译器的设计复杂程度。例

20、13:#includevoid main()void *f; int i=1,*p; f=&i p=(int*)f; f=p; coutp*p; coutf*f; /void的值不能显示,故编译报错例13中划有下划线的部分在C语言中是可以省去的。但在C+语言中则绝对不能省去。例中的f是void型指针,可被解释成能指向任何类型变量,所以能被任何型指针所赋值。而指针p的类型是int,在C+语言中就不能自动地通过缺省类型转换将非int类型的地址赋予它。所以只能用(int*)来声明强制类型转换。2.8int与char不再等价在C语言中,char类型(如A)同int类型同样占用2B的空间(假设机器字长为

21、16位),所以有时认为二者可以等价。在C+语言中则非如此。字符类型的长度计量真正成为按单字节为单位计算了。所以在使用时要特别注意。比如sizeof(A)的值为 l,而sizeof(65)的值为2,两者不一致。3C+语言中函数的新特性 C+语言中的函数除了继承C语言中函数的全部语法规则之外还围绕类数据类开发了一些新的语法规则,本节将着重讨论这些新特点及其应用。3.1函数声明、定义和引用的三个步骤 同C语言一样,编制C+语言中的一个函数也要经过先声明(用prototype specification来declare该函数的主要特征往返传送的数据类型)、再定义( Function Design函数的

22、具体过程编写)和函数引用( Function Call)三个步骤。通常C语言中的前两步往往可以合并在一起实现。而在C+语言中不仅不提倡这样的编程形式,而且在某些特定条件(如将在下一章中讲述的友元类函数)下甚至是不允许的。合并的另一个蔽端就是在函数重载(马上讲到)的情况下,很难使人看清不同重载之间的区别。所以应养成将声明与定义分别编写的编程习惯。C+语言编译器较之C语言编译器更加严格地检查一个函数的人口与出口(与面向对象的设计原则相吻合)的各参量,而且这些只有在函数原型( Function Prototype )的声明处最突出也最清晰。此外函数的预声明也是不可缺省的。不仅自编的函数要先声明后定义

23、,而且对C+语言系统提供的那些函数的预声明也不可缺省。如在C语言中使用printf函数时就可以省去“#include”的语句(当然编译器会报警告性错误),而在C+语言中,编译器就要报错。函数的声明与定义要在函数的返回类型,函数名和参数的类型及数量这三条线上保持一致。例14:void Pr(int k,float f); /也可写成void Pr(int,float); void Pr(int i,float f) /参数类型与数量一致即可3.2函数间传递参数的使用 C+语言的这一要素与C语言没有本质的不同。唯一的区别是C+语言允许使用其特有的引用类型做参数。作为参数传递的引用类型实际上是传递指

24、针地址的另一种形式,因而这种参数也具有双向传输的特性。3.3函数的返回值 C+语言内函数返回值的使用与C语言基本一致,不同之处在于:无缺省返回类型 在C语言中,当不声明函数的返回值类型时,其缺省返回类型为“int”。而C+语言却规定所声明的任何函数都必须指定返回值类型。无类型也要指定为“void”,否则将认为是语法错误。引用类型可以充当返回值的类型初学C+语言的读者不易理解使用引用类型作为返回值的类型的深刻含义,试以下例来体会这一技术概念:例15:struct Dtunsigned int mm,dd,yy;Dt& fun()Dt dt1=12,31,1994;return dt1;void

25、main() Dt dt2; dt2=fun(); cout”Current Date is ”dt2.yy.dt2.mm.dt2.dd;在例15中尽管“dt1”是函数fun内的局部变量,但由于函数fun的返回值的类型是引用类型而导致返回的实际内容是“dt1”的地址,所以“dt2”仍可获取“dt1”的值。要提请读者注意的是dt1是在函数fun执行完毕并完成其返回赋值操作后才被系统释放的。如将本例改为下例的形式则更为有趣。例16:struct Dtunsigned int mm,dd,yy;Dt& fun(dt &pdt)return pdt;void main() dt dt1=12,31,1

26、994; dt dt2; fun(dt2)=dt1;例16中带下划线的语句效果等同于“dt2=dt1”。既然函数可以带回的是一个指向同一地址单元标识,当然可以将其插入到各种运算中从而构成复杂的运算表达式了。由此也可以体现出引用类型的特殊用途之处了。3.4内联(inline)函数 内联函数是C+语言特有的一种函数附加类别,是通过在函数声明之前插入“inline”保留字实现的。编译器会将编译后的全部内联函数的目的机器代码复制到程序内所有的引用位置并把往返传送的数据也都溶合进引用位置的计算当中,从而大大减少系统为函数引用引用和返回的例行开销。显然这是以增加程序代码空间为代价换来的。所以对于含有较多计

27、算语句且引用又不太频繁的函数不宜使用内联特性。而且即使插入了inline关键字的函数也要由编译器按一定准则判断是否按其指定的inline的方式处理。对不同公司和不同版本的C+编译器,这个判决也不一样。有些(如Turbo C+ 1.0)还会对这类函数中的循环语句(如for、while等)报警或报错。例17:#includeinline int add(int,int);void main() cout”2+2=”add(2,2); cout”100+50=”add(100,50);inline int add(int x,int y) return (x+y); 看了上面的介绍,似乎内联函数的效

28、果极象宏(Marco),其实这是误解。如前所说,内联函数是将编译后的目标机器代码插复制到程序内所有的引用位置,而宏则是将其源程序插在源程序的引用处再一起参加编译。此两种码的插入阶段完全不一样,效果自然也就不一样了。用下面的例子来说明它们之间有时发生的不同效果便可以一目了然了。先定义一个宏“#define sq(x) x*x”,当程序中引引用的是sq(3)时,编译器解释成3*3=9。但下面的两个引用结果却出现了奇异: sq(1+2); /结果显示为:5(即按1+2*1+2计算)将sq的定义改为sq(x) (x)*(x);后才能避免此类错误的发生。但是若继续另一种引用则奇异仍能出现: int i=

29、2; sq(+i); /结果显示为:12(即按3*4计算)这些结果是由于宏是作为一种源码先插入到了引用位置后再被编译固化在主程序中的原因而引起的。而将sq定义改为:“inline int sq(int x)return(x*x);”后,上面的奇怪结果就不会出现了。由此可见,内联函数仍是函数的一种,而不能看成宏。3.5C+语言中函数的缺省参数 C+语言中的函数的另一个新特性就是可以定义缺省参数值。其语法就是在函数声明中的参数右侧用等号与希望的缺省值相连接。凡要声明缺省值的参数一律自右向左排列在参数表内。如下的声明格式就是错误的:void sub(int, int=0,int);而应改成:void

30、 sub(int, int,int=0);当函数引用发生后,从声明有缺省值的某个实参开始的全部实参都可以缺省,这时在形参表中等号后的各“缺省值”将起实参的传递作用。例18:# includeint sub(int x=1,int y=1) return x-y;void main()cout sub() sub(5)sub(5,8);例18结果显示分别为:0(即按1-l计算)、4(即按5-1计算)和-3(即按5-8计算)。可见这一新特点大大提高了C+语言内函数的灵活性。诸如某些要求带初始化参数的函数都可用此法满足了。3.6函数的重裁(Overload function) 在C+语言中,将含有不

31、同的数量参数或参数类型的一系列同名函数称为重载函数。此种函数族的出现就形成了用同一函数名重复、衍生出多种不同用途的函数的效应,也被称为为重载(Overload)。重载函数具有极高的实用价值。比如要用同一个函数名dsp来显示不同类型的变量值,就可以声明一系列重载函数来实现。例19:#includevoid dsp(int i)cout”Value is “ i;char dsp(char c)cout”Character is ”c;return c;void dsp() ;引用时只要给出同一函数名dsp并赋予实参即可。C+语言系统会自动判断出应引用重载函数中的哪个函数。这是其明显的优点。又如(

32、下例较复杂,供参考)某个DOS系统下运行的系统根据内部的运算需要在屏幕上分别使用不完全一致的前后背景的视口窗和窗口窗。根据已学的图形函数知识,这两种窗口的设置与所引用的函数都应是两套体系。在使用C语言的设计过程中,只能编制出两个不同名的函数予以应对。这便使得设计出的系统不易维护。这时便可以使用C+语言的重载函数来统一实现此功能。例20:#include#includevoid setwin(short ,short);void setwin( int,double,double);void main() _setvideomode(18); setwin(200,60); setwin(0,1

33、.,1.); getchar(); _setvideomode(_DEFAULTMODE);void setwin(short xx,short yy) _setvieworg(xx,yy); _rectangle(_GBORDER,0,0,639-xx,479-yy);void setwin (int c,double xx,double yy) _setwindow(c,0.,0.,xx,yy); _setcolor(2); _rectangle_w(_GBORDER,0.01,0.01,.678*xx,.864*yy);例20中为绘出两个设置的窗口,分别用rectangle函数画出窗口的

34、边界(视口窗为亮白色,窗口窗为暗绿色)。例中的0.678和0.864分别是根据本例测算出的X、Y方向的边界系数用以使暗绿色的窗口呈现在白色窗口内。很明显在引用一侧的主程序,目标是非常突出了。而对同一个setwin,由于所给参数的类型不同,则可引用不同的setwin函数。后面的各种绘图函数都可以如法炮制了。将来即使C+语言再扩充类似的新函数,只要相应增加声明,定义和引用三部内容即可,再也不用对原程序大动干戈地修改了。其实在C+语言中,不仅函数可以重载,算符也可以由用户任意重载(后面将讲到)。可以说,C+语言的重载无处不在。在使用函数重载功能时,一定要明确其概念,否则很容易出错。如: void s

35、etwin(); int setwin();就不是重载。因为”返回值类型不同”不是重载函数的区分条件,所以编译器将认为是“ambiguous”。又如: void setwin(int x); short setwin(short y);确是重载,因为在C+语言中int与short不再是同义的。这样一来就极易产生了一个问题,在执行时如遇setwin(9);语句,C+语言应选哪一个呢?经试验,先调的是类型自动转换时优先级较高的int型。所以在遇有类型转换时,或者使用强制类型转换或者避免设计这样的重载函数。当重载与缺省参数两种特性同时使用时,更容易发生问题。例21:#includevoid df(i

36、nt x=-1,int y=0)coutx+y;void df(char x=A)cout”x=”x;void main()df();例21中的两个df重载函数都使用了缺省参数,面对此种情况,编译器实在无法知道函数main()中“df();”引用究竟是指向谁的,于是要报出“ambiguous”的错误。所以在实践中使用重载功能一定要弄清目的和环境后再设计。3.7函数型指针C语言就有函数型指针,只是过去由于极少使用,又加之易与指针型函数相混淆,所以许多C语言教材中都不介绍或极少介绍。而在C+语言中,这种函数指针与上面讲过的重载函数相结合可以产生极为方便的函数族引用,所以在此有必要详细讲解这种指针的

37、应用。在C语言中设计一个功能选单时,一般都会用到switch-case方式来判断用户的选择,然后引用相应的函数。转到C+语言中,由于有了重载,似乎可以把这一系列的函数都合并为一个,或者也可利用缺省参数功能来解决函数中参数个数的不同。但是当所有的功能函数都没有参数(如void)或各函数的参数数量及类型完全一致时,就不能再用重载功能了。这时可以利用函数型指针所指向的某个函数首地址来决定应去引用哪个函数。现仍以一个具体例子来说明函数型指针的应用。例22:#include# include# include# includevoid file_type(char*);void file_del(cha

38、r*);void (*file_op)(char*)=file_type,file_del;void main() const char *comm=“type ”,” del ” ; char *s=” ”; int cho; char *buff=” ”; printf(“Please input the file name:”); cins;printf(“Please Choice the function number:n 1Display the filen /2Erase the file n CHOICE:”); /选择l为type文件名 cincho; /选择2为del文件名

39、 cho-; strcpy(buff,commcho); strcat(buff,s); file_opcho(buff);void file_type(char* f1)strcat(f1,”|more”);void file_del(char* f2)system(f2);例22进行了两种文件操作:1一显示;2一删除。例22中利用 void(*file_op)(cha*)=;声明了一个函数型指针数组,并同时赋予初值一两个功能函数的首地址。这样操作选择就不用switch-case语句,使程序大为简化。书写这里面的声明语句要注意三点:函数型指针名两侧的括号不能省略,否则其形式将成为指针型函数的

40、返回值类型了。在引用函数型指针时,其名前的“*”和外面的括号可省略。如下的两种引用形式则是等价的:double max(int,int);double rs;double (*pf)(int,int);pf=&max;rs=(*pf)(3.14,1.22);rs=pf(9.0,2.4);函数型指针的参数和返回值类型必须与所指的函数声明相一致。如下的声明组合就是错误的:void max(int,int);double (*pf)(int,int)=&max; /返回值类型不一致3.8函数模板(Template)在设计模型中常会要求函数的参数的类型能够动态地适应各种数据类型,这使人们很容易地会利用

41、重载。但所带来的负面效应便是程序代码的冗长。而C+语言的模板确是一种更好的解决方案。当设计者还不能确定将程序在未来运行时所使用的某种数据类型时,便可使用模板来代之。编译器则会把编译时产生的符号表保留至运行阶段,根据实时传递的数据类型再临时确定分配存储空间算法。模板技术是C+语言实现多态的一种重要的手段。模板声明的语法格式为:template上述格式中内的内容称为模板参数表,其中的“class”是保留关键字。替代类型标识符通常使用大写字母串,如:template,则“T”可以在程序运行时被任何C+语言支持的数据类型所取代。如有两个以上的模板参数时,使用逗号分隔,如:“template”。由于模板

42、是专门为函数按排的,所以模板声明语句必须置于与其相关的函数声明或定义语句之前,但附于函数声明语句和定义语句前的模板参数表的替代类型标识符可以不一致。例23:#include#define PI 3.templatedouble Circle_Square(T);void main() int r1=1; double r2=2.0; coutThe first circle square is Circle_Square(r1)endl The second circle square is Circle_Square(r2)endl;template /替代类型标识符可以不同于声明语句dou

43、ble Circle_Square(TX x) return x*x*PI;模板也可以用做函数的返回类型。但充当返回类型的模板最好也充当该函数的参数,否则(即使使用强制类型转换)该函数的返回类型也将是不易确定的。C+编译器只得选用缺省的int类型充当返回类型。当使用模板的函数与重载函数同时出现在一个程序体内时,C+编译器的求解次序是先重载;后模板;再强制,最后报错。如在下例中对作为实参的“r3”首先引用的是重载函数“long double Circle_Square(long x)”。例24:#include#define PI 3.templatedouble Circle_Square(T

44、);long double Circle_Square(long x) return x*x*PI;void main() int r1=1; double r2=2.0; long r3=3; coutThe first circle square is Circle_Square(r1)endl The second circle square is Circle_Square(r2)endl The third circle square is Circle_Square(r3)endl;templatedouble Circle_Square(T x) return x*x*PI;3.

45、9异常处理程序在执行时经常会出现一些违反设计期望的异常情况(如除零)。早期的解决方法多是由操作系统利用中断代为处理。由于这种解决方法强行中止了应用程序的运行,一些大型的应用系统的设计者便提出在可以允许的范围内由应用程序自身来处理一般性的软件运行异常和错误,从而提高软件系统的容错能力。因此能够设计大型软件系统的C+语言便提供了异常处理的功能。异常处理有三个部分构成:异常检测条件的设定、异常检测的捕获和异常检测的处理。它们分别对应了“try”、“throw”和“catch”三个保留关键字。这三者的流程关系可用下图表示:异常判决表达式与(throw)“扔出异常标志”的动作被包容在try过程当中。而异

46、常检测的处理则是由catch() 函数完成的,即由catch() 函数检测并处理某个throw扔出的错误标识。显然,catch() 函数不能与try过程相脱离。因此,C+语言的语法规定一个try过程与至少一个catch() 函数是对应的存在的。在书写顺序上总是呈现为try catch() 格式。而对catch() 函数则有以下的语法格式规定:catch() 函数即没有头文件声明也没有任何返回值;catch() 函数的参数的个数和类型必须与throw语句后变量的个数和类型相一致;在try 和catch() 语句之间不得插入任何其它C+语句。例25:#includedouble divide(do

47、uble,double) ;void main() double f1=0.0,f2=0.0; try coutf1/f2=divide(f1,f2)n; catch(double err) coutA divided number was found.The number is err”n”; double divide(double x,double y) if(y=0.)throw 1.0E-323; /在Pentium芯片的计算机上实测的最小正值为:1.0E-323 return x/y;除了本例的常规应用外,C+的异常处理还有下述的一些特点:一个try语句可以后跟一个以上的带有不同类

48、型参数的catch() 语句。用此种结构语句可适用于由一条try语句而导致扔出的多种数据类型的设计。比如,在上例中可再声明一个divide()的重载函数并配套定义相应的catch() 语句即可。try语句及其过程体内的函数仍可嵌套定义自身的try语句而形成堆栈式异常处理。在此种结构中产生的异常信息将按执行的先后顺序被压入堆栈。而不同位置的catch() 语句也将自内向外顺序地提取属于自身类型的当前栈顶的异常信息。若程序中没有安排与某个throw语句扔出的数据类型相匹配的catch() 处理语句,一旦相应的错误发生则会导致整个系统被操作系统强行终止。例26:#includevoid f()throw Is that you fred?n;void g()throw -1;void h() tryf();g(); catch(char* ps)cout*ps; throw yes,its me

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论