1、第四章 过程抽象函数第1页本章内容n n 子程序概念子程序概念n n C+C+函数函数n n 变量局部性变量局部性n n 标识符作用域标识符作用域n n 递归函数递归函数n n 函数名重载函数名重载n n 带缺省值形式参数带缺省值形式参数n n 内联函数内联函数n n 条件编译条件编译n n 标准库函数标准库函数第2页子程序n n子程序是取了名一段程序代码,在程序中经过名字来使用它们。n n数据传递全局变量(不好):全部子程序都能访问到变量。全局变量(不好):全部子程序都能访问到变量。参数:形式参数(形参)和实在参数(实参)。参数:形式参数(形参)和实在参数(实参)。传递方式有:传递方式有:n
2、 n值传递:把实参值复制一份给形参。值传递:把实参值复制一份给形参。n n地址或引用传递:把实参地址传给形参。地址或引用传递:把实参地址传给形参。第3页n n子程序作用:降低重复代码,节约劳动力;降低重复代码,节约劳动力;实现过程抽象,即,一个子程序代表一个功效,实现过程抽象,即,一个子程序代表一个功效,使用者只需知道所使用子程序功效,而无须关使用者只需知道所使用子程序功效,而无须关心它们是怎样实现。为处理复杂程序设计问题心它们是怎样实现。为处理复杂程序设计问题提供了一个伎俩。提供了一个伎俩。第4页函数n n函数是C+提供用于实现子程序语言成分。n n函数定义:n n ()n n描述了函数返回
3、值类型,n n可认为任意C+数据类型。n n当返回值类型为void时,它表示函数没有返回值。n n用于标识函数名字,用标识符表示。n n描述函数形式参数,由零个、一个或多个形参说明(用逗号隔开)组成,形参说明格式为:n n 第5页 为为一一个个 ,用用于于实实现现对对应应函数功效。函数功效。n n函数体内能够包含函数体内能够包含returnreturn语句,格式为:语句,格式为:returnreturn;return;return;n n当当函函数数体体执执行行到到returnreturn语语句句时时,函函数数马马上上返返回回到到调调用者。用者。n n在函数体中不能用在函数体中不能用在函数体中
4、不能用在函数体中不能用gotogoto语句转出函数体。语句转出函数体。语句转出函数体。语句转出函数体。第6页函数例子int factorial(int n)/求n阶乘 int i,f=1;for(i=2;i=n;i+)f*=i;return f;第7页函数调用 n n对于定义一个函数,必须要调用它,它函数体才会执行。n n函数调用格式以下:()由由零零个个、一一个个或或多多个个表表示示式式组组成成(逗逗号号分割)分割)实实参参个个数数和和类类型型应应与与对对应应函函数数形形参参相相同同。类类型型假假如如不不一一样,编译器会试图进行隐式转换。样,编译器会试图进行隐式转换。n n不能用goto语句
5、从函数外转入函数体第8页函数调用例子.int main()int main()int x;int x;cout cout x;cin x;cout Factorial of x is cout Factorial of x is factorial(x)/factorial(x)/调用阶乘函数调用阶乘函数 endl;endl;return 0;return 0;第9页函数调用执行过程n n计计算算实实参参值值(对对于于多多个个实实参参,C+C+没没有有要要求求计计算算次序次序););n n把实参分别传递给被调用函数形参;把实参分别传递给被调用函数形参;n n执行函数体;执行函数体;n n函函数
6、数体体中中执执行行returnreturn语语句句返返回回函函数数调调用用点点,调调用用点点取取得得返返回回值值(假假如如有有返返回回值值)并并执执行行调调用用之之后后操作。操作。第10页函数申明 n n程序中调用全部函数都要有定义。n n假如函数定义在其它文件(如:C+标准库)中或定义在根源文件中使用点之后,则在调用前需要对被调用函数进行申明。n n函数申明格式以下:();/);/函数原型函数原型函数原型函数原型 externextern(););在函数申明中,在函数申明中,在函数申明中,在函数申明中,中中中中能能能能够够够够只列出形参只列出形参只列出形参只列出形参类类类类型而不型而不型而不
7、型而不写形参名写形参名写形参名写形参名。第11页基于功效分解和复合程序设计n n人们在设计一个复杂程序时,经常会用到功效人们在设计一个复杂程序时,经常会用到功效分解分解和和复合复合两种伎俩:两种伎俩:功效分解:在进行程序设计时,首先把程序功效分解成若功效分解:在进行程序设计时,首先把程序功效分解成若干子功效,每个子功效又能够分解成若干子功效,等等,干子功效,每个子功效又能够分解成若干子功效,等等,从而形成了一个自顶向下(从而形成了一个自顶向下(top-downtop-down)、逐步精化)、逐步精化(step-wisestep-wise)设计过程。)设计过程。功效复合:把已经有(子)功效逐步组
8、合成更大(子)功功效复合:把已经有(子)功效逐步组合成更大(子)功效,从而形成一个自底向上(效,从而形成一个自底向上(bottom-upbottom-up)设计过程。)设计过程。n n子程序为基于功效分解和复合程序设计提供了基础:子程序为基于功效分解和复合程序设计提供了基础:一个子程序代表了一个功效。一个子程序代表了一个功效。第12页例:用函数实现求小于n全部素数。#include#include#include#includeusingnamespacestd;usingnamespacestd;boolis_prime(intn);/boolis_prime(intn);/函数申明函数申明
9、函数申明函数申明voidprint_prime(intn,intcount);/voidprint_prime(intn,intcount);/函数申明函数申明函数申明函数申明intintmainmain()()inti,n,count=1;inti,n,count=1;coutcoutn;/cinn;/从键盘输入一个正整数从键盘输入一个正整数从键盘输入一个正整数从键盘输入一个正整数if(n2)return-1;if(n2)return-1;cout2,;/cout2,;/输出第一个素数输出第一个素数输出第一个素数输出第一个素数for(i=3;in;i+=2)for(i=3;in;i+=2)i
10、f(if(is_primeis_prime(i)(i)count+;count+;print_primeprint_prime(i,count);(i,count);coutendl;coutendl;return0;return0;第13页boolis_prime(intn)boolis_prime(intn)inti,j;inti,j;for(i=2,j=sqrt(n);i=j;i+)for(i=2,j=sqrt(n);i=j;i+)if(n%i=0)returnfalse;if(n%i=0)returnfalse;returntrue;returntrue;voidprint_prime
11、(intn,intcount)voidprint_prime(intn,intcount)coutn,;coutn,;if(count%6=0)coutendl;if(count%6=0)coutendl;第14页函数参数传递 n nC+提供了两种参数传递机制:值传递值传递地址和引用传递地址和引用传递n nC+默认参数传递方式是值传递。第15页值传递n n在函数调用时,采取类似赋值操作形式把实参值传给形参。n n函数执行过程中,经过形参取得实参值,n n函数体中对形参值改变不会影响对应实参值。第16页值参数传递例子#include#include using namespace std;usi
12、ng namespace std;double power(double x,int n);double power(double x,int n);int main()int main()double a=3.0,c;double a=3.0,c;int b=4;int b=4;c=power(a,b);c=power(a,b);cout a ,b ,c endl;cout a ,b ,c=0)if(n=0)while(n 0)while(n 0)product*=x;product*=x;n-;n-;elseelsewhile(n 0)while(n 0)product/=x;produc
13、t/=x;n+;n+;return product;return product;第18页n n执行执行mainmain时,产生三个变量(分配内存空间)时,产生三个变量(分配内存空间)a a、b b和和c c:a:3.0 b:4 c:?a:3.0 b:4 c:?n n调用调用powerpower函数时,又产生三个个变量函数时,又产生三个个变量x x、n n和和productproduct,然后分别用,然后分别用a a、b b以及以及1.01.0对它们初始化:对它们初始化:a:3.0 b:4 c:?a:3.0 b:4 c:?x:3.0 n:4 product:1.0 x:3.0 n:4 prod
14、uct:1.0n n函数函数powerpower中循环结束后(函数返回前):中循环结束后(函数返回前):a:3.0 b:4 c:?a:3.0 b:4 c:?x:3.0 n:0 product:81.0 x:3.0 n:0 product:81.0n n函数函数powerpower返回后:返回后:a:3.0 b:4 c:81.0a:3.0 b:4 c:81.0第19页变量局部性n n在C+中,依据变量定义位置,把变量分成:全局变量和局部变量。全局变量全局变量是指在函数外部定义变量,它们普通是指在函数外部定义变量,它们普通能被程序中全部函数使用(静态全局变量除外)。能被程序中全部函数使用(静态全局
15、变量除外)。局部变量局部变量是指在复合语句中定义变量,它们只是指在复合语句中定义变量,它们只能在定义它们复合语句(包含内层复合语句)能在定义它们复合语句(包含内层复合语句)中使用。中使用。第20页全局变量和局部变量例子int x=0;/int x=0;/全局变量全局变量void f()void f()int y=0;/int y=0;/局部变量局部变量x+;/OKx+;/OKy+;/OKy+;/OKa+;/Errora+;/Error int main()int main()int a=0;/int a=0;/局部变量局部变量f();f();a+;/OKa+;/OKx+;/OKx+;/OKy+
16、;/Error y+;/Error while(x10)while(x10)int b=0;/int b=0;/局部变量局部变量 a+;/OK a+;/OKb+;/OKb+;/OKx+;/OKx+;/OK b+;/Errorb+;/Errorreturn 0;return 0;第21页变量生存期(存放分配)n n把程序运行时一个变量占有内存空间时间段称为该变量生存期。n nC+把变量生存期分为:静态静态:内存空间从程序开始执行时就进行分配,直到程:内存空间从程序开始执行时就进行分配,直到程序结束才收回它们空间。全局变量含有静态生存期序结束才收回它们空间。全局变量含有静态生存期 。自动自动:内存
17、空间在程序执行到定义它们复合语句(包含:内存空间在程序执行到定义它们复合语句(包含函数体)时才分配,当定义它们复合语句执行结束时,函数体)时才分配,当定义它们复合语句执行结束时,它们空间将被收回。局部变量和函数参数普通含有自动它们空间将被收回。局部变量和函数参数普通含有自动生存期。生存期。动态动态 :内存空间在程序中显式地用:内存空间在程序中显式地用newnew操作或操作或mallocmalloc库函数分配、用库函数分配、用deletedelete操作或操作或freefree库函数收回。动态变库函数收回。动态变量含有动态生存期。量含有动态生存期。第22页存放类修饰符 n n在定义局部变量时,可
18、认为它们加上存放类修饰符来指出它们生存期。n nauto:使局部变量具有自动生存期。局部变量默认存放类为auto。n nstatic:使局部变量具有静态生存期,它只在函数第一次调用时进行初始化,以后调用中不再进行初始化,它值为上一次函数调用结束时值。n nregister:使局部变量也具有自动生存期,由编译程序根据CPU存放器使用情况来决定是否存放在存放器中。第23页void f()void f()int x=0;int x=0;static int y=1;static int y=1;register int z=0;register int z=0;x+;y+;z+;x+;y+;z+;c
19、out x y z endl;cout x y z endl;n n第一次调用第一次调用f f时,输出:时,输出:1 2 11 2 1n n第二次调用第二次调用f f时,输出:时,输出:1 3 11 3 1第24页程序实体在内存中安排n n静态数据区静态数据区用于全局变量、用于全局变量、staticstatic存放类局部变量以及常存放类局部变量以及常量内存分配量内存分配 。n n代码区代码区用于存放程序指令,对用于存放程序指令,对C+C+程序而言,代码区存程序而言,代码区存放是全部函数代码;放是全部函数代码;n n栈区栈区用于用于autoauto存放类局部变量、函数形式参数以及函数调存放类局部
20、变量、函数形式参数以及函数调用时相关信息(如:函数返回地址等)内存分配;用时相关信息(如:函数返回地址等)内存分配;n n堆区堆区用于动态变量内存分配。用于动态变量内存分配。静态数据区代码区栈区堆区第25页C+程序多模块结构 n n逻辑上逻辑上,一个,一个C+C+程序由一些全局函数(区分于类程序由一些全局函数(区分于类定义中组员函数)、全局常量、全局变量定义中组员函数)、全局常量、全局变量/对象以及对象以及类定义组成,其中必须有且仅有一个名字为类定义组成,其中必须有且仅有一个名字为mainmain全全局函数。函数内部能够包含形参、局部常量、局部变局函数。函数内部能够包含形参、局部常量、局部变量
21、量/对象定义以及语句。对象定义以及语句。n n物理上物理上,能够按某种规则对组成,能够按某种规则对组成C+C+程序各个逻辑程序各个逻辑单位(全局函数、全局常量、全局变量单位(全局函数、全局常量、全局变量/对象、类等)对象、类等)定义进行分组,分别把它们放在若干个源文件中,组定义进行分组,分别把它们放在若干个源文件中,组成成程序模块程序模块。n n程序模块是为了便于从物理上对程序进行组织、管理程序模块是为了便于从物理上对程序进行组织、管理和了解,便于多人合作开发一个程序。和了解,便于多人合作开发一个程序。n n程序模块是可单独编译程序单位。程序模块是可单独编译程序单位。第26页C+模块组成n n
22、一个C+模块普通包含两个部分:接口(接口(.h.h文件文件 ):给出在本模块中定义、提供):给出在本模块中定义、提供给其它模块使用一些程序实体(如:函数、全给其它模块使用一些程序实体(如:函数、全局变量等)申明;局变量等)申明;实现(实现(.cpp.cpp文件):模块实现给出了模块中程文件):模块实现给出了模块中程序实体定义。序实体定义。n n下面是一个由三个模块(file1、file2和main)组成C+程序。第27页/file1.h/file1.hextern int x;/extern int x;/全局变量全局变量x x申明申明extern double y;/extern doubl
23、e y;/全局变量全局变量y y申明申明int f();/int f();/全局函数全局函数f f申明申明/file1.cpp/file1.cppint x=1;/int x=1;/全局变量全局变量x x定义定义double y=2.0;/double y=2.0;/全局变量全局变量y y定义定义int f()/int f()/全局函数全局函数f f定义定义 int m;/int m;/局部变量局部变量mm定义定义.m+=x;/m+=x;/语句语句.return m;return m;第28页/file2.hvoid g();/全局函数g申明/file2.cpp#include file1.h
24、 /把文件把文件file1.hfile1.h中内容包含进来中内容包含进来void g()/全局函数g定义 double z;/局部变量z定义.z=y+10;/语句.第29页/main.cpp/main.cpp#include file1.h#include file1.h /把文件把文件file1.hfile1.h中内容包含进来中内容包含进来#include file2.h#include file2.h /把文件把文件file2.hfile2.h中内容包含进来中内容包含进来int main()/int main()/全局函数全局函数mainmain定义定义 double r;/double
25、r;/局部变量局部变量r r定义定义.r=x+y*f();/r=x+y*f();/语句语句.g();/g();/语句语句.第30页标识符作用域 n n为了对程序中实体名字进行管理,引进了标识符为了对程序中实体名字进行管理,引进了标识符作作用域用域概念。概念。n n一个定义了标识符有效范围(能被访问程序段)称一个定义了标识符有效范围(能被访问程序段)称为该标识符作用域。为该标识符作用域。n nC+C+把标识符作用域分成若干类,其中包含:把标识符作用域分成若干类,其中包含:局部作用域局部作用域 全局作用域全局作用域 文件作用域文件作用域 函数作用域函数作用域 函数原型作用域函数原型作用域 类作用域
26、类作用域 名空间作用域名空间作用域第31页局部作用域n n在函数定义或复合语句中、从标识符定义点开始到函数定义或复合语句结束之间程序段。n nC+中局部常量名、局部变量名/对象名以及函数形参名含有局部作用域。n n假如在一个标识符局部作用域中包含内层复合语句,而且在该内层复合语句中定义了一个同名不一样实体,则外层定义标识符作用域应该是从其潜在作用域中扣除内层同名标识符作用域之后所得到作用域。第32页void f()void f().x./Error.x./Errorint x;/int x;/外层外层x x定义定义.x./.x./外层外层x xwhile (.x.)/while (.x.)/外
27、层外层x x .x./.x./外层外层x xdouble x;/double x;/内层内层x x定义定义.x./.x./内层内层x x.x./.x./外层外层x x 第33页全局作用域n n在函数级定义标识符含有在函数级定义标识符含有全局作用域全局作用域。n n全局变量名全局变量名/对象名、全局函数名和全局类名作用域对象名、全局函数名和全局类名作用域普通含有全局作用域,它们在整个程序中可用。普通含有全局作用域,它们在整个程序中可用。n n假如在某个局部作用域中定义了与某个全局标识符同假如在某个局部作用域中定义了与某个全局标识符同名标识符,则该全局标识符作用域应扣掉与之同名局名标识符,则该全局
28、标识符作用域应扣掉与之同名局部标识符作用域。部标识符作用域。n n在局部标识符作用域中若要使用与其同名全局标识符,在局部标识符作用域中若要使用与其同名全局标识符,则需要用全局域选择符(则需要用全局域选择符(:)对全局标识符进行修饰)对全局标识符进行修饰(受限)。(受限)。n n把全局标识符申明放在某个把全局标识符申明放在某个.h.h文件中,在需要使用这文件中,在需要使用这些全局标识符源文件中用些全局标识符源文件中用#include#include编译预处理命令把编译预处理命令把申明文件包含进来。申明文件包含进来。第34页double x;/外层x定义void f()int x;/内层x定义.x
29、./内层x.:x./外层x第35页文件作用域n n在全局标识符定义中加上在全局标识符定义中加上staticstatic修饰符,则该全局标修饰符,则该全局标识符就成了含有文件作用域标识符,它们只能在定义识符就成了含有文件作用域标识符,它们只能在定义它们源文件中使用。它们源文件中使用。n nC+C+中关键词中关键词staticstatic有两个不一样含义。有两个不一样含义。在局部变量定义中,在局部变量定义中,staticstatic修饰符用于指定局部变量采取修饰符用于指定局部变量采取静态存放分配;静态存放分配;而在全局标识符定义中,而在全局标识符定义中,staticstatic修饰符用于把全局标识
30、符修饰符用于把全局标识符作用域改变为文件作用域。作用域改变为文件作用域。n n普通情况下,含有全局作用域标识符主要用于标识被普通情况下,含有全局作用域标识符主要用于标识被程序各个模块共享程序实体,而含有文件作用域标识程序各个模块共享程序实体,而含有文件作用域标识符用于标识在一个模块内部共享程序实体。符用于标识在一个模块内部共享程序实体。第36页/file1.cpp/file1.cppstatic int y;/static int y;/文件作用域文件作用域static void f()/static void f()/文件作用域文件作用域./file2.cpp/file2.cppextern
31、 int y;extern int y;extern void f();extern void f();void g()void g().y./Error .y./Error f();/Error f();/Error 第37页函数作用域n n语句标号是唯一含有函数作用域标识符,它们在定义它们函数体中任何地方都能够访问。n n函数作用域与局部作用域区分是:函数作用域包含整个函数,而局部作用域是从定函数作用域包含整个函数,而局部作用域是从定义点开始到函数定义或复合语句结束。义点开始到函数定义或复合语句结束。在函数体中,一个语句标号只能定义一次,即使在函数体中,一个语句标号只能定义一次,即使是在内
32、层复合语句中,也不能再定义与外层相同是在内层复合语句中,也不能再定义与外层相同语句标号。语句标号。第38页void f()void f().goto L;/OKgoto L;/OK.L:.L:.goto L;/OKgoto L;/OK.void g()void g().goto L;/Errorgoto L;/Error.第39页名空间作用域n n对于一个多文件组成程序,有时见面临一个问题:在一个源文件中要用到两个分别在另外两个源文件中定义不一样全局程序实体(如:全局函数),而这两个全局程序实体名字相同。n nC+提供了名空间(namespace)设施来处理上述名冲突问题。在一个名空间中定义全
33、局标识符,其作用域为该在一个名空间中定义全局标识符,其作用域为该名空间。名空间。当在一个名空间外部需要使用该名空间中定义全当在一个名空间外部需要使用该名空间中定义全局标识符时,可用该名空间名字来修饰或受限。局标识符时,可用该名空间名字来修饰或受限。第40页3、/模块模块2 2namespace Bnamespace B int x=0;int x=0;void f()void f().A:x./A.A:x./A中中x x A:f();/AA:f();/A中中f f.B:x./B.B:x./B中中x xB:f();/BB:f();/B中中f fusing namespace A;using na
34、mespace A;.x./A.x./A中中x x f();/Af();/A中中f f.B:x./B.B:x./B中中x xB:f();/BB:f();/B中中f fusing A:f;.A:x./A/A中中x x f();/A/A中中f f.B:x./B.B:x./B中中x xB:f();/BB:f();/B中中f f/模块31、2、第41页递归函数n n函数调用是能够嵌套。假如一个函数在其函数体中直接或间接地调用了自己,则该函数称为递归函数。第42页n n直接递归void f()void f().f().f().n n间接递归extern void g();extern void g();
35、void f()void f().g().g().void g()void g().f().f().第43页递归函数作用 n n在程序设计中经常需要实现重复性操作。循环为实现重复操作提供了一个路径。n n实现重复操作另一个路径是采取递归函数。n n“分而治之”(Divide and Conquer)设计方法:把一个问题分解成若干个子问题,而把一个问题分解成若干个子问题,而每个子问题每个子问题性质与原问题相同性质与原问题相同,只是在规模上比原问题要小。,只是在规模上比原问题要小。每个子问题求解过程能够采取与原问题相同方式每个子问题求解过程能够采取与原问题相同方式来进行。来进行。n n递归函数为上
36、述设计方法提供了一个自然、简练实现机制 第44页例:求第n个fibonacci 数(递归解法)int fib(int n)if(n=1)return 0;else if(n=2)return 1;else return fib(n-2)+fib(n-1);第45页递归函数执行过程/用递归函数求用递归函数求n!n!intf(intn)intf(intn)if(n=0)if(n=0)return1;return1;elseelsereturnn*f(n-1);returnn*f(n-1);第46页递归条件和结束条件n n在定义递归函数时,一定要对两种情况给出描述:递归条件递归条件。指出何时进行递归
37、调用,它描述了问。指出何时进行递归调用,它描述了问题求解普通情况,包含:分解和综合过程。题求解普通情况,包含:分解和综合过程。结束条件结束条件。指出何时不需递归调用,它描述了问。指出何时不需递归调用,它描述了问题求解特殊情况或基本情况题求解特殊情况或基本情况第47页例:解汉诺塔问题 汉诺塔问题汉诺塔问题:有:有A A,B B,C C三个柱子,柱子三个柱子,柱子A A上穿有上穿有n n个大小个大小不一样圆盘,大盘在下,小盘在上。现要把柱子不一样圆盘,大盘在下,小盘在上。现要把柱子A A上全部圆盘上全部圆盘移到柱子移到柱子B B上,要求每次只能移动一个圆盘,且大盘不能放在上,要求每次只能移动一个圆
38、盘,且大盘不能放在小盘上,移动时可借助柱子小盘上,移动时可借助柱子C C。编写一个。编写一个C+C+函数给出移动步函数给出移动步骤,如:骤,如:n=3n=3时,移动步骤为:时,移动步骤为:A AB,AB,AC,BC,BC,AC,AB,CB,CA,CA,CB,AB,AB B。A B C第48页n n当n=1时,只要把圆盘从A移至B就能够了(输出:AB)。而当n大于1时,我们能够把该问题分解成下面三个子问题:1.把把n-1n-1个圆盘从柱子个圆盘从柱子A A移到柱子移到柱子C C。2.把第把第n n个圆盘从柱子个圆盘从柱子A A移到柱子移到柱子B B。3.把把n-1n-1个圆盘从柱子个圆盘从柱子C
39、 C移到柱子移到柱子B B。n n上面子问题1和3与原问题相同,只是盘子个数少了一个;子问题2是移动一个盘子简单问题。第49页#include#include using namespace std;using namespace std;void hanoi(char x,char y,char z,int n)/void hanoi(char x,char y,char z,int n)/把把n n个圆盘从个圆盘从x x表示表示 /柱子移至柱子移至y y所表示柱子。所表示柱子。if(n=1)if(n=1)cout 1:x cout 1:x y endl;/y endl;/把第把第1 1个个
40、/盘子从盘子从x x表示柱子移至表示柱子移至y y所表示柱子。所表示柱子。elseelse hanoi(x,z,y,n-1);/hanoi(x,z,y,n-1);/把把n-1n-1个圆盘从个圆盘从x x表示柱子移至表示柱子移至 /z /z所表示柱子。所表示柱子。cout n :x cout n :x y endl;y-数组首地址数组首地址 函数名函数名-函数首地址函数首地址 等等等等n n比如,对于下面重载函数定义:比如,对于下面重载函数定义:void print(int);void print(int);void print(double);void print(double);void p
41、rint(char);void print(char);下面函数调用:下面函数调用:print(1);print(1);绑定到函数:绑定到函数:void print(int);void print(int);print(1.0);print(1.0);绑定到函数:绑定到函数:void print(double);void print(double);print(a);print(a);绑定到函数:绑定到函数:void print(char);void print(char);第54页提升匹配n n按整型提升规则提升n n把float提升到doublen n把double提升到long doub
42、len n比如,对于下述重载函数:void print(int);void print(int);void print(double);void print(double);依据提升匹配,下面函数调用:print(a);print(a);绑定到函数:绑定到函数:void print(int);void print(int);print(1.0f);print(1.0f);绑定到函数:绑定到函数:void print(double);void print(double);第55页标准转换匹配n n任何算术类型能够相互转换n n枚举类型能够转换成任何算术类型n n零能够转换成任何算术类型或指针类型
43、n n任何类型指针能够转换成void*n n派生类指针能够转换成基类指针n n每个标准转换都是平等。第56页n n比如,对于下述重载函数:void print(char);void print(char);void print(char*);void print(char*);依据标准转换匹配,下面函数调用:print(1);print(1);绑定到函数:绑定到函数:void print(char);void print(char);print(0);print(0);绑定失败绑定失败第57页带缺省值形式参数n n在C+中允许在定义或申明函数时,为函数一些参数指定默认值。假如调用这些函数时没有
44、提供对应实参,则对应形参采取指定默认值,不然对应形参采取调用者提供实参值。n n比如,对于下面函数申明:void print(int value,int base=10);void print(int value,int base=10);n n下面调用:print(28);/28print(28);/28传给传给valuevalue;1010传给传给basebaseprint(32,2);/28print(32,2);/28传给传给valuevalue;2 2传给传给basebase第58页n n在指定函数参数默认值时,应注意下面几点:有默认值形参应处于形参表右部。比如:有默认值形参应处于形
45、参表右部。比如:n nvoid f(int a,int b=1,int c=0);/OKvoid f(int a,int b=1,int c=0);/OKn nvoid f(int a,int b=1,int c)void f(int a,int b=1,int c);/Error;/Error 对参数默认值指定只在函数申明处有意义。对参数默认值指定只在函数申明处有意义。在不一样源文件中,对同一个函数申明能够对在不一样源文件中,对同一个函数申明能够对它同一个参数指定不一样默认值;在同一个源它同一个参数指定不一样默认值;在同一个源文件中,对同一个函数申明只能对它每一个参文件中,对同一个函数申明只
46、能对它每一个参数指定一次默认值。数指定一次默认值。第59页处理小函数低效问题n n因为函数调用是需要开销,尤其是对一些小函数频繁调用将使程序效率有很大降低。n nC+提供了两种处理上述问题方法:宏定义宏定义内联函数内联函数 第60页宏定义 n n在C+中,利用一个编译预处理命令:宏定义能够实现类似函数功效:#define#define凵凵()凵凵比如:比如:#define#define凵凵max(a,b)max(a,b)凵凵(a)(b)?(a):(b)(a)(b)?(a):(b)cout max(x,y);cout(b)?(a):(b)(a)(b)?(a):(b)max(x+1,y*2)max
47、(x+1,y*2)将被替将被替换换成:成:n n(x+1)(y*2)?(x+1):(y*2)(x+1)(y*2)?(x+1):(y*2)n n不进行参数类型检验和转换。n n不利于一些工具对程序处理。第62页内联函数 n nC+C+提供了另外一个处理函数调用效率不高问题设施:内提供了另外一个处理函数调用效率不高问题设施:内联函数。联函数。n n内联函数是指在函数定义中,能够在函数返回类型之前加上内联函数是指在函数定义中,能够在函数返回类型之前加上一个关键词一个关键词inlineinline,比如:,比如:inline int max(int a,int b)inline int max(int
48、 a,int b)return ab?a:b;return ab?a:b;n n内联函数作用是内联函数作用是提议提议编译程序把该函数函数体展开到调用点。编译程序把该函数函数体展开到调用点。n n内联函数形式上属于函数,它遵照函数一些要求,如:参数内联函数形式上属于函数,它遵照函数一些要求,如:参数类型检验与转换。类型检验与转换。n n使用内联函数时应注意以下几点:使用内联函数时应注意以下几点:编译程序对内联函数限制。编译程序对内联函数限制。内联函数名含有文件作用域。内联函数名含有文件作用域。第63页编译预处理命令n nC+程序中能够写一些供编译程序使用命令:编译预处理命令。n n编译预处理命令
49、不是C+程序所要完成功效,而是用于对编译过程给出指导,其功效由编译预处理系统来完成。n n编译预处理命令主要有:文件包含命令(文件包含命令(#include#include)宏定义(宏定义(#define#define)命令)命令条件编译命令条件编译命令第64页条件编译n n编译程序依据不一样情况来选择需编译程序代码。n n条件编译作用:基于多环境程序编制基于多环境程序编制 程序调试程序调试第65页基于多环境程序编制#ifdef UNIX./适合于UNIX环境代码#else./适合于其它环境代码#endif./适合于各种环境代码第66页程序调试n n加入调试信息#ifdef DEBUG#ifd
50、ef DEBUG././调试信息调试信息#endif#endifn n利用标准库#include /#include /或或 .assert(x=1);assert(x=1);第67页条件编译命令惯用格式#ifdef/#ifndef#ifdef/#ifndef 1#else#else 2#endif#endifn n上述条件编译命令含义是:假如上述条件编译命令含义是:假如 有定义有定义(#ifdef#ifdef)或无定义()或无定义(#ifndef#ifndef),则编译),则编译 1,不然编译,不然编译 2,其中,其中,#else#else分支能够省略。分支能够省略。第68页条件编译命令另一