C++及Windows可视化程序设计第4章.ppt

上传人:豆**** 文档编号:25160422 上传时间:2022-07-10 格式:PPT 页数:134 大小:1.26MB
返回 下载 相关 举报
C++及Windows可视化程序设计第4章.ppt_第1页
第1页 / 共134页
C++及Windows可视化程序设计第4章.ppt_第2页
第2页 / 共134页
点击查看更多>>
资源描述

《C++及Windows可视化程序设计第4章.ppt》由会员分享,可在线阅读,更多相关《C++及Windows可视化程序设计第4章.ppt(134页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。

1、C+及及Windows可视可视化程序设计第化程序设计第4章章4.7 函数模板4.8 解题算法知识实验习题C+语言的模块设计离不开函数,函数设计更离不开参数。掌握函数设计和调用的正确方法,是程序设计的基本功。正确设计函数原型和参数类型,不仅能保证函数的正确性,而且能提高程序设计的效率。本章除介绍函数调用、递归调用以及函数调用中的参数替换和返回值等问题之外,还将结合软件编程技术的发展,讨论函数指针、内联函数、函数重载、函数模板及算法知识等。在提出结构化程序设计之前,对软件发展影响最大的是子程序。结构化程序设计要求将任务细化到具体的模块中去,并保证各个模块任务独立,这一般借助子程序实现。在C+语言中

2、,子程序相当于函数。一般来讲,面向过程的C+源程序是由若干个函数组成的。运行时,程序从主函数main()开始执行,到main()的终止行结束。其他函数由main()或别的函数或自身调用后组成可执行程序。在面向对象程序设计中,成员函数也是函数,只是它们的类型及其返回值更复杂些。4.1 函数基础知识1. 函数值和return语句一般情况下,函数必须返回与函数声明相一致的值作为函数的值。函数返回使用如下形式实现: return (表达式);称return为返回语句。这里的表达式的值就是要返回的函数值。表达式两边的圆括号可有可无。4.1.1 函数基本要素return语句在一个函数里可以多次使用,但返回

3、值的类型必须一致且与函数的类型说明一致。当函数不需要带值返回时,将函数直接定义为void类型,最为方便。这样就不必在函数体内使用return语句。实际上,最后一个大括号“”有return语句的作用(函数末尾隐含有一个return语句)。若函数不带值返回,实际上并不是不返回什么值,而是返回一个不定值。因为不考虑使用,所以尽管返回的是不定值,也就没有多大关系了。也可以在函数体内使用不带表达式的return语句,即 return;【例4.1】 作为认识返回值的练习,写一个具有两个参数的函数max,比较这两个参数的大小,并把大者作为函数的返回值。下面的主函数调用max函数,执行该程序,x的值就等于a、

4、b中大的一个。为了分析方便,使用注释为程序语句编号。 #include /1 using namespace std; /2 double max(double,double); /3 void main() /4 double a=2.5,b=3.39,x; /5 x=max(a,b); /6 coutx=xm2)return m1; /10 else return m2; /11 /122. 函数原型声明第3行是函数max的原型声明,编译系统在编译到第6行时,会检查max的参数及返回值类型是否与函数声明一致。编译到函数的定义语句第9行时,还将检查max的定义是否与事先声明的一致。如果发生不

5、一致的情况,编译系统就要给出警告。应养成将所有函数集中进行函数原型声明的习惯。一般可以声明在头文件中,或者在主函数之前。3. 工作过程说明 这个程序是由两个函数,即主函数main和函数max组成的,并且main函数调用max函数(见第6行)。 被调用函数max里的参数m1和m2是形参(见第9行)。在调用max函数时,形参要被实参替换,如第6行所示,形参m1和m2被实参a和b替换。实参不能变化,如第5行所示,a、b分别被赋值为2.5和3.39。 在main函数中调用max函数(即执行第6行)时,实际是执行912行的内容。 max函数里使用两个return语句,用来把max函数里所求的最大值,作为

6、max函数的返回值赋值给main函数里面的变量x。4. 函数参数的说明方式程序中max函数的定义方式是目前流行的方式,称为现代方式。另一种定义方式为: double max(m1,m2) double m1,m2; /函数体这是最早使用的方式,不过现在的编译系统都支持这两种方式。作为程序员,不仅应该都熟悉,而且要特别注意这种早期方式。原因如下: 目前的数据类型品种多,标识符也长,变量名字也很长。这样一来,如果使用现代方法,反而不容易区分,可读性差。 Windows 编程时,因为数据结构复杂,所以API函数也使用第2种方式书写。例如下面的Windows函数: int PASCAL WinMain

7、(hInstance, hPrevInstance,lpCmdLine,nCmdShow) HANDLE hInstance; /当前实例句柄 HANDLE hPrevInstance;/前一个实例句柄 LPSTR lpCmdLine; /命令行参数 int nCmdShow; /窗口显示方式 /函数体 有时需要对函数的参数进行直接说明,这时只能使用后一种形式,例如上面函数就对参数进行了注释。5. 函数体内的变量为局部变量可以将函数max的定义改写如下: double max(double m1,double m2) double x; if(m1m2) x=m1;else x=m2;retu

8、rn x;main函数内部和max函数内都有变量x,两个变量x都是在各自的“”内声明的变量,这样的变量叫做局部变量。虽然它们使用了相同的变量名,但互不影响。函数的调用是在表达式、语句或参数中直接写出函数名,并用实参代替形参。一旦出现被调用的函数,就要转去执行这个函数,并将该函数执行结果返回来。根据被调用函数在源程序中出现的位置,把函数调用分为3种调用形式:语句调用、表达式调用和参数调用。1. 函数语句调用被调用函数作为一个独立的语句出现在源程序中,这种语句就叫函数语句。这种调用很简单,只要把被调用函数的函数名直接写出来,并以实参替换原来的形参即可。4.1.2 函数调用形式函数调用也可以嵌套,且

9、与函数的编写顺序没有关系。如下例所示。 【例4.2】 演示嵌套函数调用与函数的编写顺序没有关系的例子。#includeusing namespace std;void r(void);/函数原型声明,函数无参数使用void标识void a(void);void d(void);void main() /使用函数语句调用r()函数 r();void a() /使用函数语句调用d()函数 couta;d(); couta;void d()coutd; void r() /使用函数语句调用a()函数coutr; a(); coutrn;运行结果: radar2. 函数表达式调用被调用函数出现在一个表

10、达式中,这种表达式也可叫做函数表达式。这种调用所适用的条件是被调用函数有返回值。【例4.1】中的语句 x=max(a,b);就是函数表达式调用。3. 函数参数调用被调用函数作为函数的一个参数(函数参数)出现。这种调用虽然形式上不同于函数表达式调用,但调用条件和注意事项与函数表达式调用是相同的。【例4.3】 函数参数调用的例子。#includeusing namespace std;double max(double,double);void main()double a=2.5,b=3.39,c=13.25;coutmax=max(c,max(a,b)m2) return m1;else re

11、turn m2;程序先调用max求a和b中的大者,再将这个返回值作为max函数的一个参数,求它与另一个数c的大者。即max(a,b)作为函数的参数。调用函数时,参数替换的实质是把实参数值赋给形参变量,这叫做传值。函数调用,一般是一个函数调用另外一个函数。此外,函数还可以自己调用自己,这种调用叫做函数的递归调用。递归调用有两种方式,一种是直接调用其本身,另一种是通过其他函数间接地调用。在这里只给出直接递归调用的例子。4.1.3 递归调用【例4.4】 求阶乘的递归调用程序。#includeusing namespace std;int factorial(int);void main()int n

12、;coutn;coutn!=factorial(n)endl;int factorial(int x) if(x=0) return 1; else return(x*factorial(x-1);运行输入: Input n=5显示结果: 5!=120main函数调用factorial函数。其中factorial有返回值,函数递归调用时,每调用一次其自动型变量就占据堆栈一个区域,供各自的调用使用。递归调用在堆栈中临时占据的存储区域是较多的,在实际运行时,递归调用的时间效率较差。函数参数的传递方式有3种: 传值、传地址和传引用。函数的参数还可以设计成默认形式,以方便使用。4.2 函数参数的传递方

13、式传值是将实参的值传递给形参,形参拥有实参的一个备份,当在函数中改变形参的值时,改变的是这个备份中的值,不会影响原来实参的值。传值方式可以防止被调用函数改变参数的原始值,这在很多场合是很重要的。传地址又简称传址,它传递的是指向参数的指针。实际上,形参传递的就是实参本身,当在函数中改变形参的值时,改变的就是原来实参的值。大多数程序设计者为提高运行效率,用结构作参数时,通常用传址而不是传值的方式。数组只能用传址方式。4.2.1 传值和传地址著名的swap函数充分地说明了传值和传址的区别。以交换两个整数为例,下面是传值的swap函数和测试程序: 【例4.5】 传值不会改变原来值的例子。#includ

14、eusing namespace std;void swap(int,int);/函数参数采用传值方式void main() int a=3,b=8; swap(a,b); /传值 coutNow a=a b=bendl;void swap(int a,int b) int temp=a; a=b; b=temp; coutin swap: a=a b=bendl;虽然swap函数内交换a和b的值,但不影响原来的值,所以程序输出结果如下: in swap: a=8 b=3 Now a=3 b=8【例4.6】 传地址改变原来值的例子。#include using namespace std;vo

15、id swap(int*,int*);/函数参数采用传地址方式void main()int a=3,b=8;swap(&a,&b); /传地址coutNow a=a b=bendl;void swap(int *a,int *b) int temp=*a; *a=*b; *b=temp; coutin swap: a=*a b=*bendl;因为实参与形参的地址相同,所以改变形参就是改变实参。输出结果如下: in swap: a=8 b=3 Now a=8 b=3C+提供引用,主要是用来建立函数参数的引用传递方式。在说明引用参数时,不需提供初始值,其初始值在函数调用时由实参提供。传引用是将对象

16、的引用作为参数传递,引用和被引用对象的地址一样,所以改变形参就是改变实参。4.2.2 传引用方式【例4.7】 通过传引用改变原来值的例子。#includeusing namespace std;void swap(int&,int&);/函数参数采用传引用方式void main() int a=3,b=8; swap(a,b); /传引用 coutNow a=a b=bendl;void swap(int&m,int&n) int temp=m; m=n; n=temp; coutin swap: m=a=m n=b=nendl;当程序中调用函数swap时,实参a和b分别初始化引用m和n,所以

17、在函数swap中,m和n分别引用a和b,对m和n的访问就是对a和b的访问,所以函数swap改变了main 函数中变量a和b的值。通过使用引用参数,一个函数可以修改另一个函数内的变量。传引用比传指针更好,所以建议使用传引用的方式。程序输出如下: in swap: m=a=8 n=b=3 Now a=8 b=3C+语言在函数调用时,引进了一种新类型的参数: 默认参数。默认参数就是不要求程序员设定该参数,而由编译器在需要时给该参数赋默认值。当程序员需要传递特殊值时,必须显式地指明。默认参数是在函数原型中说明的。默认参数可以多于1个,但必须放在参数序列的后部,例如: int SaveName(char

18、 *first, char *second= , char *third= , char *fourth= );4.2.3 默认参数这种方式表明在实际调用函数SaveName时,如果不给出参数second、third和fourth,则取默认值。如果一个默认参数需要指明一个特定值,则在其之前的所有参数都必须赋值。在上例中,如果需给出参数third的值,则必须同时也给first和second赋值,例如: int status=SaveName(Alpha, Bravo, Charlie );【例4.8】 设计一个最多可求4个整数的最大者的函数。#includeusing namespace std

19、;int max(int m1,int m2,int m3=0,int m4=0) int max1=(m1m2)?m1: m2;int max2=(m3m4)?m3: m4;if(m3=0&m4=0) return max1;if(m4=0) max2=m3;return(max1max2)?max1: max2;void main()coutmax(2,17) max(56,8) max(2,17,56)=max(2,17,56) max(2,17,56,8)= max(2,17,56,8)endl max(-17,-5)=max(-17,-5) max(-17,-5,-2)=max(-1

20、7,-5-2) max(-17,-5,-70)= max(-17,-5,-70)endl;求最大值至少要有2个参数,故选2个默认参数。输出结果如下:17 56 max(2,17,56)=56 max(2,17,56,8)=56max(-17,-5)=-5 max(-17,-5,-2)=-2 max(-17,-5,-70)=-5思考题:这个程序不允许哪种特殊情况出现?一定要将函数原型表达正确,然后采取最方便的方法赋参数。下面是一些注意事项。1. 传递指针【例4.9】 为指针赋参数的方式选取不合适的例子。#includeusing namespace std;void swap(int *,int

21、 *);void main()int a=3,b=8;int *p1=&a,*p2=&b;/多余的方式4.2.4 正确选择函数原型及传递参数swap(p1,p2);/可以直接使用swap(&a,&b);coutNow a=a b=bendl;void swap(int *p1,int *p2) int temp=*p1; *p1=*p2; *p2=temp; coutin swap: a=*p1 b=*p2endl;虽然函数原型参数的类型是指针,但可以直接让它指向对象地址,即 int *p1=&a;是完全正确的。这里执意产生指针,毫无必要。2. 传递数组名数组名就是存储数组的首地址。数组名作为

22、参数传递时,就是传递的地址,因此被调用函数能够改变数组原来的内容。下面给出传递数组名实例。【例4.10】 传递数组名实例。#includeusing namespace std;void swap(int); /数组原型使用“类型 ”的形式void main()int a=3,8;swap(a); /传递数组名coutNow a=a0 b=a1endl;void swap(int a) int temp=a0; a0=a1; a1=temp; coutin swap: a=a0 b=a1endl;输出结果为: in swap: a=8 b=3 Now a=8 b=33. 传递结构对象如传递结构

23、对象,则是传值方式,被调用函数也不会改变结构对象原来的值。【例4.11】 传递递结构对象实例。#include using namespace std;struct LISTint a,b;d=3,8;void swap(LIST);/使用结构对象void main()swap(d); /传递对象cout Now a=d.a b=d.bendl;void swap(LIST s) int temp=s.a; s.a=s.b; s.b=temp; coutin swap: a=s.a b=s.b;函数swap不修改原来的值,输出为: in swap: a=8 b=3Now a=3 b=8如果想修

24、改原结构对象的内容,可传递结构对象的引用或指针,推荐使用引用。下面将它进行局部修改,以便用来传引用。void swap(LIST&);/使用引用的函数原型声明void main() swap(d);/传引用cout Now a=d.a b=d.b;void swap(LIST &s) int temp=s.a; s.a=s.b; s.b=temp; coutin swap: a=s.a b=s.bendl;程序正确交换a和b的值。输出为: in swap: a=8 b=3Now a=8 b=34. 传递类的对象传递类的对象与传递结构对象类似。【例4.12】 传递string类的对象。#incl

25、ude#includeusing namespace std;void swap(string&,string&);/参数为string类对象的引用void main()string a(first),b(second);swap(a,b);/传递引用对象cout Now a=a b=bendl;void swap(string&a,string&b) string temp=a; a=b; b=temp; coutin swap: a=a b=b;输出结果为: in swap: a=second b=first Now a=second b=first如果函数原型为“void swap(st

26、ring,string);”,传递的是类的对象,则不修改原来的值。5. 使用const保护数据采用const声明传递函数参数,可以避免被调用函数修改实参的值。【例4.13】 演示不可改变参数b的实例。#includeusing namespace std;void swap(int&,const int);void main()int a=30,b=18;swap(a,b);cout Now a=a b=bendl;void swap(int&a,const int b) a=a+b; coutin swap: a=a b=b;不允许swap函数改变参数b,输出为: in swap: a=48

27、 b=18 Now a=48 b=18【例4.14】 不允许改变作为参数传递的字符串内容的实例。#include#includeusing namespace std;void change(const string&);void main()string str(Can you change it?);change(str);coutstrendl;void change(const string&s) string s2=s+ No!;couts2endl;参数传递使用const修饰,程序输出如下: Can you change it? No! /函数内不能修改 /只能使用 Can you

28、 change it? /原内容不变用const修饰传递参数,意思是通知函数,它只能使用参数而无权修改它。这主要是为了提高系统的自身安全。C+中普遍采用这种方法。C+函数的返回值类型可以是除数组和函数以外的任何类型。定义一个函数,要正确选择函数返回值。非void类型的函数必须向调用者返回一个值。该值可以是标量对象,也可以是复合对象。标量对象指那些声明为基本类型的对象,返回值置于寄存器中。数组只能返回地址。复合对象是指结构或类的对象。返回类对象的情况将在第5章介绍。返回结构类型对象时,是逐个字节地拷贝过来的。4.3 深入讨论函数返回值当函数返回值是指针或引用对象时,需要特别注意: 函数返回所指的

29、对象必须继续存在,因此不能将函数内的局部对象作为函数的返回值。虽然在C+中允许返回一个指向局部静态对象的指针或引用,但最好不要这样做。函数可以返回一个引用,将函数说明为返回一个引用的主要目的是为了将该函数用在赋值运算符的左边。函数原型的表示方法为: 数据类型& 函数名(参数列表);4.3.1 返回引用的函数【例4.15】 返回引用的函数。#include using namespace std;int a=2,4,6,8,10,12;/全局数组int& index(int i);/返回引用的函数原型声明void main()index(3)=16;/将a3改为16coutindex(3)end

30、l;/输出16int& index(int i)/函数定义 return ai;/返回指定下标的整数数组内容在其他情况下,一个函数是不能直接用在赋值运算符左边的。在定义返回引用的函数时,注意不要返回对该函数内的局部对象的引用。例如: int & fun() int a; /声明的局部对象 /函数的其他内容 return a;/返回局部对象 由于局部对象的生存期仅局限于函数内部,当函数返回时,局部对象就消失了,因此,上述函数返回一个无效的引用。函数的返回值可以是存储某种类型数据的内存地址(例如变量的地址、数组的首地址及指针变量的地址),称这种函数为指针函数。指针函数的一般定义形式为: 类型标识符

31、*函数名(参数列表);4.3.2 返回指针的函数【例4.16】 使用函数input 输入一组数并返回一个指针,然后由主函数main将这组数显示出来的例子。#includeusing namespace std;float *input(int&); /声明返回指针的函数void main()int num;float *data; /声明指针data=input(num); /调用函数,返回指针赋给dataif(data) /data不空,输出所指内容 for(int i=0; inum; i+) /使用指针的下标形式 cout datai ; /循环输出 delete data; /释放内存

32、空间float *input(int& n) /定义返回指针的函数 cout n; if(n=0)return NULL; /输入个数不合理则退出 float *buf=new floatn; /根据输入数据数量申请空间 if(buf=0)return NULL;/没申请到则退出 for(int i=0;ibufi; return buf; /返回指针程序运行示范如下: Input number: 312.25 45.32 78.9412.25 45.32 78.94函数input用于接收用户输入,数据为float类型,它首先提示用户输入需输入的数据的个数,然后分配一块存储区域来保存用户输入的

33、数据。若函数在运行时返回一个有效的指针,则这个指针指向的内存供用户输入数据,数据的个数可从input的引用参数中得知。输入的数据个数小于或等于零,或内存分配失败时,函数都返回一个空指针值,这个值可作为程序异常的标志。因为在C+中,除了内存分配失败之外,new不会返回空指针,并且没有任何对象的地址值为零。调用input函数时,仅需一个和该函数返回类型一致的对象中保存input函数返回的指针,并在判断这个指针值非零的情况下,使用这个指针所指向的内存中的数据。调用input函数的函数应负责释放由input函数分配的内存。一般说来,指针所指向的对象的生存期不应低于该指针的生存期。【例4.17】 函数返

34、回对象的例子。#include #include using namespace std;string input(const int); /声明返回string类型的函数void main()int n;coutn; /接收要处理的字符串数量string str=input(n);/将函数返回的对象赋给对象strcoutstrendl;4.3.3 返回对象的函数string input(const int n) string s1,s2;/建立两个string类的对象(均为空串)for(int i=0;is1; /接收n个字符串 s2=s2+s1+ ; /将接收的字符串相加 return s

35、2;/返回string对象函数input用来接收字符串对象,然后将string的对象s2作为返回值。运行演示如下:Input n=3zhang san fengzhang san feng如果用函数返回值作为另一个函数的参数,这个返回值必须与参数的类型一致。可以通过函数指针将函数作为参数传给其他函数,以便能够创造出功能很强的高级函数系统。函数指针比较复杂,在Windows编程中也很重要,放在4.4节中介绍。4.3.4 函数返回值作为参数函数在内存中有确定的物理地址,该地址能够赋给指针。这是因为函数在编译时,它的源代码转换成了目标代码,同时确定了函数的入口地址。程序调用函数,也就是指向了这个入口

36、地址。指向函数的指针实际上包含了函数的入口地址,所以赋给指针的地址就是函数的入口地址,从而该指针就用来代替函数名。这就使得函数可以作为实参传递给其他函数。由此可见,可以将一个指向函数的指针传递给函数,或放置在数组中提供给其他对象使用。4.4 函数指针可以把一个函数地址赋给一个函数指针,然后再通过该函数指针来完成对函数的调用。【例4.18】 使用函数指针求整数a和b中小者的程序。#includeusing namespace std;int min(int,int); /声明函数原型void main()int(*p)(int,int);/声明函数指针pint a,b,c;cinab;p=min

37、; /函数指针p指向函数min的地址c=(*p)(a,b); /使用函数指针p调用函数min4.4.1 通过函数指针完成对函数的调用coutmin=cendl;int min(int x,int y)/函数min的定义 if(xy) return x;else return y;1. 函数指针定义函数指针定义形式如下: 数据类型标识符 (*指针对象名) (函数参数的 数据类型列表);语句“int (*p)(int,int);”仅仅说明定义的p是一个指向函数的指针,此函数返回整型值。p并不是固定指向哪一个函数的,而只是表示定义了这样一个类型的对象,专门用来存放函数的入口地址。在程序中把哪一个函数

38、的地址赋给它,它就指向哪一个函数。在一个程序中,一个函数指针对象可以先后指向不同的函数。从这一点上看,它跟过去介绍的指针对象具有相同的性质。声明函数指针时,只需要给出函数参数的数据类型,不需要给出参数名。如果给出也可以,只不过编译系统不理睬参数名而已。在本例题中,下面两种形式是等效的: int(*p)(int,int); /只给参数类型 int(*p)(int a,int b);/给出参数类型和参数名也可以使用typedef定义,例如: typedef int(*FUN)(int a,int b); FUN p;则对象p为一个指向原型为 int (int,int)的函数的指针。2. 函数指针对

39、象赋值给函数指针对象赋值时,只需要给出函数名而不必给出参数。因为语句 p=min;是将函数入口地址赋给指针对象p,而不涉及到实参与形参的结合问题。注意: 不允许写成“p=min(a,b);”的形式。前面讲过,数组名代表数组起始地址,这里的函数名则代表函数的入口地址。因为在C+中,单独一个函数名(其后不跟一对圆括号)被自动地转换为指向该函数的指针(函数的第1条指令的地址)。当函数地址被置入一个指针对象中时,可以通过该指针对象调用该函数。这里的p就是指向函数min的指针对象,它和min都指向函数的开头,调用p就是调用min。与过去所讲的对象的重要区别是: 它只能指向函数的入口处,而不能指向函数中间

40、的具体指令。因此,*(p+1)、p+n、p-及p+等运算对它都是没有意义的。3. 调用方法语句“c=(*p)(a,b);”的含义是: 调用由p指向的函数,实参为a和b,得到的函数值再赋给事先定义的整型变量c。函数指针对象调用函数时,只需将(*p)代替函数名即可(p为指针对象名),在(*p)之后的括号中根据需要写上实参。这条语句与语句“c=min(a,b);”是等价的。4. 函数声明必须声明函数的原型。现在是用函数名(例如min)作右值,后面没有括号和参数,编译系统无法判断它们究竟是对象名还是函数名,故要对它们加以声明。本例的声明如下: int min(int,int);5. 调用指向函数语句(

41、*p)(a,b)将调用由p指向的函数,把a 和 b作为实参传递给函数。圆括号内也可不含参数,但圆括号必须存在,下列语句以相似的方式调用无参数的函数: (*p)();p也需要使用圆括号括起来,以强制运算“*”在被调用前使用。若不加括号,则 int *p();就变成了一个返回整数指针的函数声明。可以用普通方式使用间接调用的函数返回结果。例如,下列语句将把函数调用返回的结果赋值到i对象。 i=(*p)(a,b);【例4.19】 输出多项式x2+5x+8和x3-6x在区间-1,+1内,增长步长为0.1时的所有结果。#includeusing namespace std;double const STE

42、P=0.1;double f1(double);/函数f1的原型声明double f2(double);/函数f2的原型声明void main()double x,(*p)(double);/声明函数指针对象pfor(int i=0; i2; i+) if(i=0) p=f1;/i为0时p指向函数f1 else p=f2;/i为1时p指向函数f2 for(x=-1; x=1; x+=STEP) /对指定函数完成计算 coutxt(*p)(x)endl; double f1(double x) /函数f1的定义 return(x*x+5*x+8); double f2(double x) /函数

43、f2的定义 return(x*x*x-6*x);上面的程序使用一个函数指针 p,完成对f1和f2两个函数的调用,这在那些有规律的多函数调用系统中,可以大大增强程序的处理能力。也可以用指向函数的函数指针对象作为参数,从而实现函数地址的传递(也就是将函数名作为实参),达到将函数作为参数传给其他函数的目的。下面用一个实例来说明具体的含义。假设已经有分别求两个数的大者、小者及平均值的3个函数max,min和mean。现在另外定义一个函数 all如下: int all(int x,int y,int(*func)(int,int) return(*func)(x,y); 4.4.2 通过函数指针对象将函

44、数作为参数传给其 他函数函数all共有3个形参,其中,有2个int形参,1个为指向函数的指针对象func。这个对象声明为 int(*func)(int,int),可用一个定义的函数代替all中的func,例如all(a,b,mean)相当于执行mean(a,b),从而输出a和b的平均值。同理,可用相同方法调用min及max,而all函数的形式一样,只是在调用时改变实参函数名而已。这就增加了函数使用的灵活性,它在大型程序设计,尤其是模块设计时特别有用。【例4.20】 完整的示例程序。#include using namespace std;int all(int,int,int(*)(int,i

45、nt);/含有函数指针的 /函数原型声明int max(int,int),min(int,int),mean(int,int);/函数原 /型声明void main()int a,b;cinab;coutmax=all(a,b,max)endl;coutmin=all(a,b,min)endl;coutmean=all(a,b,mean)y)?x: y;int min(int x,int y) return(xy)?x: y;int mean(int x,int y) return(x+y)/2);输入58 62输出max=62min=58mean=60【例4.21】 求函数10 x2-9x+

46、2在区间 0,1内x以0.01的增量变化的最小值。#include using namespace std;double const s1=0.0;double const s2=1.0;double const step=0.01;double func(double);double value(double(*)(double);void main()double(*p)(double);p=func;/指向目标函数cout最小值是: value(p)endl;double func(double x) /目标函数return(10*x*x-9*x+2);double value(doub

47、le(*f)(double)/定义求最小值函数,它 /包括函数指针 double x=s1,y=(*f)(x); while(x(*f)(x) y=(*f)(x); x+=step; return y;运行结果: 最小值是:-0.025函数指针的目标函数必须已经存在,才能被引用。本例中p函数指针的目标函数func已经在p被调用之前声明,也已经通过语句 p=func;指向它的目标函数func。下面的程序使用isnumber来判定一个输入字符是否属于数字字符,程序如下: #includeusing namespace std;int isnumber(char c)return(c=0 & c=9

48、)? 1: 0;void main()char c;cout c;if(isnumber(c)coutYou entered a digit;4.5 内联函数else cout=0 & c=9)? 1: 0);这种替换用手工来做是很繁琐的,可以让C+编译程序来做,这只要在函数isnumber的定义前加上关键字inline即可,即定义为: inline int isnumber(char c)C+编译器在遇到对函数isnumber 调用的地方都用这个函数体替换该调用表达式。使用关键字inline说明的函数称内联函数。在C+中,除具有循环语句、switch语句的函数不能说明为内联函数外(编译器会对

49、这类错误给出警告信息),其他函数都可以说明为内联函数。使用内联函数,加快了程序执行速度,但如果函数体语句多,则会增加程序代码的大小。使用小的内联函数在代码速度和大小上可以取得折衷,其他情况下取决于程序员是追求代码速度,还是追求代码的规模。由于编译器必须知道内联函数的函数体,才能进行内联替换,因此,内联函数必须在程序中第一次调用此函数的语句出现之前被编译器看见。例如,上面的程序可采用下述方式。#includeusing namespace std;inline int isnumber(char c) return(c=0 & c=9)? 1: 0;void main()/.C+允许为同一个函数

50、定义几个版本,这称为函数重载。函数重载使一个函数名具有多种功能,即具有“多种形态”,称这种形态为多态性。在下面的例子中,为求两个数值中的最大者,设计一个名为max的函数,并为不同参数类型各设计一个函数体。同理,也可用这个函数名设计一个具有3个整型参数,从而求出3个整数最大值的函数体。当然,也可以为具有3个参数的max函数设计不同参数类型的函数体。4.6 函数重载【例4.22】 函数重载产生多态性的例子。#includeusing namespace std;double max(double,double);/2个实型参数的函数原型int max(int,int); /2个整型参数的函数原型c

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

当前位置:首页 > pptx模板 > 企业培训

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号© 2020-2023 www.taowenge.com 淘文阁