您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 薪酬管理 > (C++-面向对象程序设计-谭浩强)第4章--函数与预处理
第4章函数与预处理4.1概述4.2定义函数的一般形式4.3函数参数和函数的值4.4函数的调用*4.5内置函数*4.6函数的重载*4.7函数模板*4.8有默认参数的函数4.9函数的嵌套调用4.10函数的递归调用4.11局部变量和全局变量4.12变量的存储类别4.13变量属性小结4.14关于变量的声明和定义4.15内部函数和外部函数4.16预处理命令4.1概述一个较大的程序不可能完全由一个人从头至尾地完成,更不可能把所有的内容都放在一个主函数中。为了便于规划、组织、编程和调试,一般的做法是把一个大的程序划分为若干个程序模块(即程序文件),每一个模块实现一部分功能。不同的程序模块可以由不同的人来完成。在程序进行编译时,以程序模块为编译单位,即分别对每一个编译单位进行编译。如果发现错误,可以在本程序模块范围内查错并改正。在分别通过编译后,才进行连接,把各模块的目标文件以及系统文件连接在一起形成可执行文件。在一个程序文件中可以包含若干个函数。无论把一个程序划分为多少个程序模块,只能有一个main函数。程序总是从main函数开始执行的。在程序运行过程中,由主函数调用其他函数,其他函数也可以互相调用。在C语言中没有类和对象,在程序模块中直接定义函数。可以认为,一个C程序是由若干个函数组成的,C语言被认为是面向函数的语言。C++面向过程的程序设计沿用了C语言使用函数的方法。在C++面向对象的程序设计中,主函数以外的函数大多是被封装在类中的。主函数或其他函数可以通过类对象调用类中的函数。无论是C还是C++,程序中的各项操作基本上都是由函数来实现的,程序编写者要根据需要编写一个个函数,每个函数用来实现某一功能。因此,读者必须掌握函数的概念以及学会设计和使用函数。“函数”这个名词是从英文function翻译过来的,其实function的原意是“功能”。顾名思义,一个函数就是一个功能。在实际应用的程序中,主函数写得很简单,它的作用就是调用各个函数,程序各部分的功能全部都是由各函数实现的。主函数相当于总调度,调动各函数依次实现各项功能。开发商和软件开发人员将一些常用的功能模块编写成函数,放在函数库中供公共选用。程序开发人员要善于利用库函数,以减少重复编写程序段的工作量。图4.1是一个程序中函数调用的示意图。图4.1例4.1在主函数中调用其他函数。#includeiostreamusingnamespacestd;voidprintstar(void)//定义printstar函数{cout″******************************″endl;//输出30个“*”}voidprint_message(void)//定义print_message函数{cout″WelcometoC++!″endl;//输出一行文字}intmain(void){printstar();//调用printstar函数print_message();//调用print_message函数printstar();//调用printstar函数return0;}运行情况如下:******************************WelcometoC++!******************************从用户使用的角度看,函数有两种:(1)系统函数,即库函数。这是由编译系统提供的,用户不必自己定义这些函数,可以直接使用它们。(2)用户自己定义的函数。用以解决用户的专门需要。从函数的形式看,函数分两类:(1)无参函数。调用函数时不必给出参数。(2)有参函数。在调用函数时,要给出参数。在主调函数和被调用函数之间有数据传递。4.2定义函数的一般形式4.2.1定义无参函数的一般形式定义无参函数的一般形式为类型标识符函数名([void]){声明部分语句}例4.1中的printstar和print_message函数都是无参函数。用类型标识符指定函数的类型,即函数带回来的值的类型。4.2.2定义有参函数的一般形式定义有参函数的一般形式为类型标识符函数名(形式参数表列){声明部分语句}例如:intmax(intx,inty)//函数首部,函数值为整型,有两个整型形参{intz;//函数体中的声明部分z=xy?x:y;//将x和y中的大者的值赋给整型变量zreturn(z);//将z的值作为函数值返回调用点}C++要求在定义函数时必须指定函数的类型。4.3函数参数和函数的值4.3.1形式参数和实际参数在调用函数时,大多数情况下,函数是带参数的。主调函数和被调用函数之间有数据传递关系。前面已提到:在定义函数时函数名后面括号中的变量名称为形式参数(formalparameter,简称形参),在主调函数中调用一个函数时,函数名后面括号中的参数(可以是一个表达式)称为实际参数(actualparameter,简称实参)。例4.2调用函数时的数据传递。#includeiostreamusingnamespacestd;intmax(intx,inty)//定义有参函数max{intz;z=xy?x:y;return(z);}intmain(){inta,b,c;cout″pleaseentertwointegernumbers:″;cinab;c=max(a,b);//调用max函数,给定实参为a,b。函数值赋给ccout″max=″cendl;return0;}运行情况如下:pleaseentertwointegernumbers:23↙max=3图4.2有关形参与实参的说明:(1)在定义函数时指定的形参,在未出现函数调用时,它们并不占内存中的存储单元,因此称它们是形式参数或虚拟参数,表示它们并不是实际存在的数据,只有在发生函数调用时,函数max中的形参才被分配内存单元,以便接收从实参传来的数据。在调用结束后,形参所占的内存单元也被释放。(2)实参可以是常量、变量或表达式,如max(3,a+b);但要求a和b有确定的值。以便在调用函数时将实参的值赋给形参。(3)在定义函数时,必须在函数首部指定形参的类型(见例4.2程序第3行)。(4)实参与形参的类型应相同或赋值兼容。例4.2中实参和形参都是整型,这是合法的、正确的。如果实参为整型而形参为实型,或者相反,则按不同类型数值的赋值规则进行转换。例如实参a的值为3.5,而形参x为整型,则将3.5转换成整数3,然后送到形参b。字符型与整型可以互相通用。(5)实参变量对形参变量的数据传递是“值传递”,即单向传递,只由实参传给形参,而不能由形参传回来给实参。在调用函数时,编译系统临时给形参分配存储单元。请注意:实参单元与形参单元是不同的单元。图4.3表示将实参a和b的值2和3传递给对应的形参x和y。图4.3图4.4调用结束后,形参单元被释放,实参单元仍保留并维持原值。因此,在执行一个被调用函数时,形参的值如果发生改变,并不会改变主调函数中实参的值。例如,若在执行max函数过程中形参x和y的值变为10和15,调用结束后,实参a和b仍为2和3,见图4.4。4.3.2函数的返回值(1)函数的返回值是通过函数中的return语句获得的。return语句将被调用函数中的一个确定值带回主调函数中去。return语句后面的括号可以要,也可以不要。return后面的值可以是一个表达式。(2)函数值的类型。既然函数有返回值,这个值当然应属于某一个确定的类型,应当在定义函数时指定函数值的类型。(3)如果函数值的类型和return语句中表达式的值不一致,则以函数类型为准,即函数类型决定返回值的类型。对数值型数据,可以自动进行类型转换。4.4函数的调用4.4.1函数调用的一般形式函数名([实参表列])如果是调用无参函数,则“实参表列”可以没有,但括号不能省略。如果实参表列包含多个实参,则各参数间用逗号隔开。实参与形参的个数应相等,类型应匹配(相同或赋值兼容)。实参与形参按顺序对应,一对一地传递数据。但应说明,如果实参表列包括多个实参,对实参求值的顺序并不是确定的。4.4.2函数调用的方式按函数在语句中的作用来分,可以有以下3种函数调用方式:1.函数语句把函数调用单独作为一个语句,并不要求函数带回一个值,只是要求函数完成一定的操作。如例4.1中的printstar();2.函数表达式函数出现在一个表达式中,这时要求函数带回一个确定的值以参加表达式的运算。如c=2*max(a,b);3.函数参数函数调用作为一个函数的实参。如m=max(a,max(b,c));//max(b,c)是函数调用,其值作为外层max函数调用的一个实参4.4.3对被调用函数的声明和函数原型在一个函数中调用另一个函数(即被调用函数)需要具备哪些条件呢?(1)首先被调用的函数必须是已经存在的函数。(2)如果使用库函数,一般还应该在本文件开头用#include命令将有关头文件“包含”到本文件中来。(3)如果使用用户自己定义的函数,而该函数与调用它的函数(即主调函数)在同一个程序单位中,且位置在主调函数之后,则必须在调用此函数之前对被调用的函数作声明。所谓函数声明(declare),就是在函数尚在未定义的情况下,事先将该函数的有关信息通知编译系统,以便使编译能正常进行。例4.3对被调用的函数作声明。#includeiostreamusingnamespacestd;intmain(){floatadd(floatx,floaty);//对add函数作声明floata,b,c;cout″pleaseentera,b:″;cinab;c=add(a,b);cout″sum=″cendl;return0;}floatadd(floatx,floaty)//定义add函数{floatz;z=x+y;return(z);}运行情况如下:pleaseentera,b:123.68456.45↙sum=580.13注意:对函数的定义和声明不是同一件事情。定义是指对函数功能的确立,包括指定函数名、函数类型、形参及其类型、函数体等,它是一个完整的、独立的函数单位。而声明的作用则是把函数的名字、函数类型以及形参的个数、类型和顺序(注意,不包括函数体)通知编译系统,以便在对包含函数调用的语句进行编译时,据此对其进行对照检查(例如函数名是否正确,实参与形参的类型和个数是否一致)。其实,在函数声明中也可以不写形参名,而只写形参的类型,如floatadd(float,float);这种函数声明称为函数原型(functionprototype)。使用函数原型是C和C++的一个重要特点。它的作用主要是:根据函数原型在程序编译阶段对调用函数的合法性进行全面检查。如果发现与函数原型不匹配的函数调用就报告编译出错。它属于语法错误。用户根据屏幕显示的出错信息很容易发现和纠正错误。函数原型的一般形式为(1)函数类型函数名(参数类型1,参数类型2…);(2)函数类型函数名(参数类型1参数名1,参数类型2参数名2…);第(1)种形式是基本的形式。为了便于阅读程序,也允许在函数原型中加上参数名,就成了第(2)种形式。但编译系统并不检查参数名。因此参数名是什么都无所谓。上面程序中的声明也可以写成floatadd(floata,floatb);//参数名不用x、y,而用a、b效果完全相同。应当保证函数原型与函数首部写法上的一致,即函数类型、函数名、参数个数、参数类型和参数顺序必须相同。在函数调用时函数名、实参类型和实参个数应与函数原型一致。说明:(1)前面已说明,如果被调用函数的定义出现在主调函数之前,可以不必加以声明。因为编译系统已经事先知道了已定义的函数类型,会根据函数首部提供的信息对函数的调用作正确性检查。有经验的程序编制人员一般都把main函数写在最前面,这样对整个程序的结构和作用一目了然,统览全局,然后再具体了解各函数的细节。此外,用函数原型来声明函数,还能减少编写程序时可能出现的错误。由于函数声明的位置与函数调用语句的位置比较近,因此在
本文标题:(C++-面向对象程序设计-谭浩强)第4章--函数与预处理
链接地址:https://www.777doc.com/doc-5702813 .html