1、 2.4 2.4 命名空间命名空间 2.4.1 2.4.1 为什么要引入为什么要引入命名空间命名空间 命名空间是随标准命名空间是随标准C+而引入的,用来防止而引入的,用来防止全局空间内的命名冲突,即重名问题。全局空间内的命名冲突,即重名问题。大型应用系统常常由许多人来设计完成,命名大型应用系统常常由许多人来设计完成,命名冲突是一种潜在的危险,程序员必须细心地定义标冲突是一种潜在的危险,程序员必须细心地定义标识符,以保证名字的惟一性。识符,以保证名字的惟一性。一个标识符可在多个命名空间中定义,它在不同一个标识符可在多个命名空间中定义,它在不同命名空间中的含义是互不相干的。这样,在一个新的命名空间
2、中的含义是互不相干的。这样,在一个新的命名空间中可定义任何标识符,它们不会与任何已有命名空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的定义都处于其它命名的标识符发生冲突,因为已有的定义都处于其它命名空间中。空间中。例如,设例如,设Bill是是X公司的员工,工号为公司的员工,工号为123,而,而John是是Y公司的员工,工号也是公司的员工,工号也是123。由于两人在不。由于两人在不同的公司工作,可以使用相同的工号来标识而不会造同的公司工作,可以使用相同的工号来标识而不会造成混乱,这里每个公司就表示一个独立的命名空间。成混乱,这里每个公司就表示一个独立的命名空间。如果两人在
3、同一家公司工作,其工号就不能相同了,如果两人在同一家公司工作,其工号就不能相同了,否则会发生混乱。否则会发生混乱。2.4.1 2.4.1 为什么要引入为什么要引入命名空间命名空间 这一特点是使用命名空间的主要理由。在大型的计算这一特点是使用命名空间的主要理由。在大型的计算机程序中,往往会出现成百上千个标识符。命名空间提供机程序中,往往会出现成百上千个标识符。命名空间提供了一种了一种隐藏区域标识符隐藏区域标识符的机制。通过将逻辑上相关的标的机制。通过将逻辑上相关的标识符组织成相应的命名空间,可使整个系统更加模块化。识符组织成相应的命名空间,可使整个系统更加模块化。在编程语言中,命名空间是一种特殊
4、的作用域,它包在编程语言中,命名空间是一种特殊的作用域,它包含了处于该作用域内的标识符,且本身也用一个标识符来含了处于该作用域内的标识符,且本身也用一个标识符来表示,这样便将一系列在逻辑上相关的标识符用一个标识表示,这样便将一系列在逻辑上相关的标识符用一个标识符组织了起来。许多现代编程语言都支持命名空间。符组织了起来。许多现代编程语言都支持命名空间。2.4.1 2.4.1 为什么要引入为什么要引入命名空间命名空间 花括号括起来的部分称声明块。声明块中可以包括:花括号括起来的部分称声明块。声明块中可以包括:类、变量(带有初始化)、函数(带有定义)等。在域类、变量(带有初始化)、函数(带有定义)等
5、。在域外使用域内的成员时,需加上名字空间名作为前缀,后外使用域内的成员时,需加上名字空间名作为前缀,后面加上面加上域操作符域操作符“:”。这里添加了名字空间名称的。这里添加了名字空间名称的成员名被称为限定修饰名。如成员名被称为限定修饰名。如:ns1:ans1:a,ns1:fun1()ns1:fun1()等等。等等。最外层的名字空间域称为全局名字空间域(最外层的名字空间域称为全局名字空间域(global global namespace scopenamespace scope),即文件域。),即文件域。2.4.2 2.4.2 如何创建命名空间如何创建命名空间2.4.2 2.4.2 如何创建命名
6、空间如何创建命名空间 名字空间域可分层嵌套,有分层屏蔽作用。例如:名字空间域可分层嵌套,有分层屏蔽作用。例如:namespacenamespace n1 n1 namespacenamespace n2 n2/名字空间嵌套名字空间嵌套 classclass matrix matrix 访问访问matrixmatrix,可写:,可写:n1:n2:matrix n1:n2:matrix。2.4.3 2.4.3 如何访问命名空间成员如何访问命名空间成员1.使用使用域操作符域操作符直接访问直接访问2.使用使用using 声明声明3.使用使用using 指令指令访问命名空间成员,有三种方法:访问命名空间
7、成员,有三种方法:ns1:a n1:n2:matrix#includeusing namespace std;namespace A int x=1;namespace B int x=2;void main()int y=x;int a=A:x;int b=B:x;coutabendl;/error C2065:x:undeclared identifier/OK使用使用using声明可只写一次声明可只写一次 限定修饰名限定修饰名using声明以关键字声明以关键字using开头,后面是被限开头,后面是被限定修饰的名字空间成员名,例如:定修饰的名字空间成员名,例如:using n1:n2:ma
8、trix;以后在程序中使用以后在程序中使用matrix时,就可以直接使时,就可以直接使用成员名,而不必使用限定修饰名。用成员名,而不必使用限定修饰名。2.使用使用using 声明声明#includeusing namespace std;namespace A int x=1;namespace B int x=2;void main()int y=x;int a=A:x;int b=B:x;coutabendl;using A:x;int a=x;使用使用using指示符,可以一次性地使名字指示符,可以一次性地使名字空间中所有成员都可以直接被使用,比空间中所有成员都可以直接被使用,比usin
9、g声明更方便。声明更方便。using指示符以关键字指示符以关键字using开头,后面开头,后面是关键字是关键字namespace,然后是名字空间名。,然后是名字空间名。3.使用使用using指示符指示符3.使用使用using指示符指示符 标准标准C+C+库中的所有组件都是在一个被称为库中的所有组件都是在一个被称为stdstd的名的名字空间中声明和定义的。因此,在采用标准字空间中声明和定义的。因此,在采用标准C+C+的平台的平台上使用标准上使用标准C+C+库中的组件,只要写上这个库中的组件,只要写上这个usingusing指示指示符,就可以直接使用符,就可以直接使用中的所有成员。中的所有成员。注
10、意:注意:如果使用了名空间如果使用了名空间stdstd,则在使用,则在使用#include#include编编译预处理命令包含头文件时,必须去掉头文件的扩展译预处理命令包含头文件时,必须去掉头文件的扩展名名.h.h,否则会出错。,否则会出错。#includeusing namespace std;namespace A int x=1;namespace B int x=2;void main()int y=x;int a=A:x;int b=B:x;coutabendl;using namespace A;int a=x+y;int y;2.8 2.8 动态内存的分配与释放动态内存的分配与释
11、放 在程序运行时可使用的内存空间称为在程序运行时可使用的内存空间称为堆堆(heap)heap),堆内存就是在程序运行时获得堆内存就是在程序运行时获得的内存空间,在程序编译和连接时不必确定的内存空间,在程序编译和连接时不必确定它的大小,它随着程序的运行过程变化,时它的大小,它随着程序的运行过程变化,时大时小,因此堆内存是动态的,堆内存也称大时小,因此堆内存是动态的,堆内存也称为动态内存。为动态内存。new运算符用于申请所需的内存空间,返回指定类型的一个指针(常量,即内存空间首地址)。它的语法格式为:=new 数据类型;其中,指针变量应预先声明,指针变量指向的数据类型与new后面的数据类型相同。若
12、申请成功,则返回分配空间的首地址赋给指针变量;否则(如没有足够的内存空间)返回0(NULL一个空指针)。例如:例如:int *p;p=new int;(20);系统为指针p p开辟了一个用来保存int类型数据的内存空间(在申请时,也可以进行初始化)。new 运算符例如:例如:int *p;p=new int20;系统为指针p p开辟了一个用来保存int类型数组的内存空间,数组中有20个元素。也可以用new运算符申请一块保存数组的内存空间,即。格式为:new 数据类型数组大小;其中,数组大小给出,指针指向分配的内存空间,指针的类型与new后的数据类型相同。new 运算符 当程序中不再使用由运算符
13、new申请的某个内存空间时,可以用delete运算符释放它。它的语法格式为:delete 指针变量;delete 常量指针变量;它的功能是释放由new申请到的内存空间。其中指针变量是指向需要释放内存空间的指针变量名字,并且delete只是删除动态内存空间,并不是将指针变量本身删除。常量可以省略,且不用考虑数组的维数。int *p1=new int;int *p2=new int 20;delete p1;delete p2;delete 运算符v 1.1.运算符返回的是一个指向所分配类型变量(对象)运算符返回的是一个指向所分配类型变量(对象)的的指针指针。对所创建的变量或对象,都是通过该指针来
14、间接操作。对所创建的变量或对象,都是通过该指针来间接操作的,而的,而。v 2.2.一般定义变量和对象时要用标识符命名,称一般定义变量和对象时要用标识符命名,称,而动态所创建的变量或对象称而动态所创建的变量或对象称。堆区是不会自动在分。堆区是不会自动在分配时做初始化的(包括清零),所以必须用初始化式(配时做初始化的(包括清零),所以必须用初始化式()来显来显式初始化。但式初始化。但v 3.3.指针变量指针变量newnew 数据类型数据类型 数组大小数组大小;请注意请注意“数组大小数组大小”不是常量表达式,即它的值不必在编不是常量表达式,即它的值不必在编译时确定,可以在运行时确定。变量译时确定,可
15、以在运行时确定。变量 n n 在编译时没有确定的在编译时没有确定的值,而是在运行中输入,值,而是在运行中输入,这一点,这一点是动态分配的优点,可克服数组是动态分配的优点,可克服数组“大开小用大开小用”的弊端,在表、的弊端,在表、排序与查找中的算法,若用动态数组,通用性更好。排序与查找中的算法,若用动态数组,通用性更好。v 4.4.。返回一个空指针(。返回一个空指针(NULLNULL),表示发),表示发生了异常,堆资源不足,分配失败。因此,一定要检查分配的生了异常,堆资源不足,分配失败。因此,一定要检查分配的内存指针是否为空,如果是空指针,则不能引用这个指针,否内存指针是否为空,如果是空指针,则
16、不能引用这个指针,否则将造成系统崩溃。则将造成系统崩溃。int *p=new int 20;if(p!=NULL)else v 5.5.。删除一个指针。删除一个指针p;p;实际意实际意思是删除了思是删除了p p所指的目标(变量或对象等),释放了它所占所指的目标(变量或对象等),释放了它所占的堆空间,而不是删除本身,释放堆空间后,成了的堆空间,而不是删除本身,释放堆空间后,成了。v 6.6.。我们也称堆空间为自由空间(我们也称堆空间为自由空间(free free storestore)就是这个原因。)就是这个原因。但必须记住释放该对象所占堆空间,但必须记住释放该对象所占堆空间,并只能释放一次,在
17、函数内建立,而在函数外释放是一件很容并只能释放一次,在函数内建立,而在函数外释放是一件很容易易的事,往往会出错。的事,往往会出错。v 7 7newnew与与delete delete 是配对使用的,是配对使用的,deletedelete只能释放堆空间。如果只能释放堆空间。如果newnew返返回的指针值丢失,则所分配的堆空间无法回收,称回的指针值丢失,则所分配的堆空间无法回收,称,同一空间重复释放也是危险的,因为该空间可能已另分配,所同一空间重复释放也是危险的,因为该空间可能已另分配,所以必须妥善保存以必须妥善保存newnew返回的指针,以保证不发生内存泄漏,也返回的指针,以保证不发生内存泄漏,
18、也必须保证不会重复释放堆内存空间。必须保证不会重复释放堆内存空间。#include using namespace std;void main()int n;int*p;coutn;if(p=new intn)=0)cout cant allocate more memory,terminating.endl;exit(1);for(int i=0;in;i+)pi=i*2;coutNow output the array:endl;for(i=0;in;i+)coutpi ;coutendl;delete p;Please input the length of the array:6Now
19、 output the array:0 2 4 6 8 102.10 2.10 引引 用用 引用是引用是C+的一个特殊的数据类型描述,用于在程的一个特殊的数据类型描述,用于在程序的不同部分使用两个以上的变量名指向同一地址,使得序的不同部分使用两个以上的变量名指向同一地址,使得对其中任一个变量的操作实际上都是对同一地址单元进行对其中任一个变量的操作实际上都是对同一地址单元进行的。在这种两个以上变量名的关系上,被声明为引用类型的。在这种两个以上变量名的关系上,被声明为引用类型的变量名则是实际变量名的的变量名则是实际变量名的别名别名。引用运算符为引用运算符为&,声明引用的一般形式为:,声明引用的一般
20、形式为:数据类型数据类型&引用变量名引用变量名=变量名;变量名;对引用操作,实际上就是对被引用的变量操作。引用对引用操作,实际上就是对被引用的变量操作。引用不是值,不占存储空间,声明引用时,目标的存储状态不不是值,不占存储空间,声明引用时,目标的存储状态不会改变。引用一旦被初始化,就不能再重新赋值。会改变。引用一旦被初始化,就不能再重新赋值。#include void main()int num=50;int&ref=num;ref+=10;coutnum=numendl;cout ref=refendl;num+=40;cout num=numendl;coutref=refendl;引用举
21、例。引用举例。(1)(1)在一行上声明多个引用型变量在一行上声明多个引用型变量(函数函数)名时,要在每个变名时,要在每个变量量(函数函数)名前都冠以名前都冠以“&”符号。符号。(2)(2)引用不是变量,所以引用本身不能被修改,在程序中引用不是变量,所以引用本身不能被修改,在程序中对引用的存取都是对它所引用的变量的存取。对引用的存取都是对它所引用的变量的存取。(3)(3)一个变量被声明为引用时必须进行初始化,除非这个一个变量被声明为引用时必须进行初始化,除非这个引用是用作函数的参数或返回值,为引用提供的初始值应引用是用作函数的参数或返回值,为引用提供的初始值应为变量。引用一旦被初始化为变量。引用
22、一旦被初始化,就不能再重新赋值。就不能再重新赋值。(4)(4)由于引用不是变量,所以,不能说明引用的引用,也由于引用不是变量,所以,不能说明引用的引用,也不能说明数组元素的类型为引用数组,或指向引用的指针。不能说明数组元素的类型为引用数组,或指向引用的指针。例如:例如:int&a5;/错误错误 int&*p;/错误错误 (5)(5)由于指针也是变量,因此可以说明对指针变量的引用。由于指针也是变量,因此可以说明对指针变量的引用。例如:例如:int*a;int*&p=a;int b;p=&b;/a/a指向变量指向变量b b (6)(6)引用与指针不同。指针的值是某一变量的内存单元地引用与指针不同。
23、指针的值是某一变量的内存单元地址,而引用则与初始化它的变量具有相同的内存单元地址。址,而引用则与初始化它的变量具有相同的内存单元地址。指针是个变量,可以把它再赋值成其它的地址,然而,建指针是个变量,可以把它再赋值成其它的地址,然而,建立引用时必须进行初始化并且决不会再指向其它不同的变立引用时必须进行初始化并且决不会再指向其它不同的变量。量。(7)(7)要注意区分引用运算符和地址运算符的区别。要注意区分引用运算符和地址运算符的区别。int num=50;int&ref=num;int*p=&ref;(8)(8)可以用一个引用初始化另一个引用。例如:可以用一个引用初始化另一个引用。例如:int n
24、um=50;int&ref1=num;int&ref2=ref1;ref2=100;/num/num为为100100 其中其中ref2ref2也是对也是对numnum的引用。的引用。(9)(9)函数调用可以作为函数调用可以作为 左值左值 引用表达式是一个左值,因此它可以出现在形、实参数引用表达式是一个左值,因此它可以出现在形、实参数的任何一方。若一个函数返回了引用,那么该函数的调用的任何一方。若一个函数返回了引用,那么该函数的调用也可以被赋值。一般说,当返回值不是本函数内定义的局也可以被赋值。一般说,当返回值不是本函数内定义的局部变量时就可以返回一个引用。在通常情况下,引用返回部变量时就可以返
25、回一个引用。在通常情况下,引用返回值只用在需对函数的调用重新赋值的场合,也就是对函数值只用在需对函数的调用重新赋值的场合,也就是对函数的返回值重新赋值的时候。避免将局部作用域中变量的地的返回值重新赋值的时候。避免将局部作用域中变量的地址返回,就使函数调用表达式作为左值来使用。址返回,就使函数调用表达式作为左值来使用。【例例2.8】【例例2.9】28 在在C+C+中,任何命名的存储区域都称为中,任何命名的存储区域都称为左值,左值,这这个存储区域的内容可以被修改。任何未命名的存储区个存储区域的内容可以被修改。任何未命名的存储区域,如堆栈中创建的临时变量,称为域,如堆栈中创建的临时变量,称为右值右值
26、;右值表示;右值表示一个表达式运算后的值,如果是基本类型,就不能修一个表达式运算后的值,如果是基本类型,就不能修改;如果是用户自定义类型,就可以被修改,且称为改;如果是用户自定义类型,就可以被修改,且称为可修改的右值。可修改的右值。对于int a(10),&ra=a;语句,下列描述错误的是()。ra是变量a的引用,即为变量的别名ra的值为10ra的地址值为&a改变ra的值为20,变量a的值仍为10ABCD提交单选题1分2.11 const2.11 const修饰符修饰符#define PI 3.1415926const double PI=3.1415926;这个常量是有类型的,它有地址,可以
27、用指针指向这这个常量是有类型的,它有地址,可以用指针指向这个值,但不能修改它。个值,但不能修改它。C+C+建议用建议用constconst取代取代#define#define定义定义常量。常量。与与#define#define定义的常量有所不同,定义的常量有所不同,constconst定义的常量可以定义的常量可以有自己的数据类型,这样有自己的数据类型,这样C+C+编译程序可以进行更加严编译程序可以进行更加严格的类型检查,具有良好的编译时的检测性。格的类型检查,具有良好的编译时的检测性。(1)(1)使用使用constconst修饰符定义常量时,必须初始化;修饰符定义常量时,必须初始化;(2)(2
28、)函数参数也可以用函数参数也可以用constconst说明,用于保证实参在该函说明,用于保证实参在该函数内部不被改动,大多数数内部不被改动,大多数C+C+编译器能对具有编译器能对具有constconst参数参数的函数进行更好的代码优化。例如,通过函数的函数进行更好的代码优化。例如,通过函数maxmax求出整求出整型数组型数组a100a100中的最大值,函数原型应该是:中的最大值,函数原型应该是:int max(const int*pa);这样做的目的是确保原数组的数据不被破坏,即在函这样做的目的是确保原数组的数据不被破坏,即在函数中对数组元素的操作只许读,不许写。数中对数组元素的操作只许读,不
29、许写。指向常量的指针是一个指向常量的指针变量。指向常量的指针是一个指向常量的指针变量。const char*pc=abcd;声明指向常量的指针变量声明指向常量的指针变量pcpc,指向一个字符串常量。,指向一个字符串常量。由于使用了由于使用了constconst,不允许改变指针所指的常量,因此以,不允许改变指针所指的常量,因此以下语句是错误的:下语句是错误的:pc3=x;但是由于但是由于pcpc是一个指向常量的普通指针变量,不是常指是一个指向常量的普通指针变量,不是常指针,因此可以改变针,因此可以改变pcpc的值。例如以下语句是允许的:的值。例如以下语句是允许的:pc=jkkk;常指针是指针本身
30、,而不是它指向的对象声明为常量。常指针是指针本身,而不是它指向的对象声明为常量。例如:例如:char*const pc=abcd;/常指针常指针这个语句的含义为:声明一个名为这个语句的含义为:声明一个名为pcpc的指针变量,该指的指针变量,该指针是指向字符型数据的常指针,用针是指向字符型数据的常指针,用“abcdabcd”的地址初始化的地址初始化该常指针。创建一个常指针,就是创建不能移动的固定该常指针。创建一个常指针,就是创建不能移动的固定指针,但是它所指的数据可以改变。例如:指针,但是它所指的数据可以改变。例如:pc3=x;/合法合法 pc=dfasdfa;/不合法不合法 整个指针本身不能改
31、变,它所指向的值也不能改变。要整个指针本身不能改变,它所指向的值也不能改变。要声明一个指向常量的常指针,二者都要声明为声明一个指向常量的常指针,二者都要声明为constconst。const char*const pc=abcd;这个语句的含义为:声明一个名为这个语句的含义为:声明一个名为pcpc的指针变量,它是的指针变量,它是一个指向字符型常量的常指针,用一个指向字符型常量的常指针,用“abcdabcd”的地址初始化该的地址初始化该指针。以下两个语句都是错误的:指针。以下两个语句都是错误的:pc3=x;/错误,不能改变指针所指的值错误,不能改变指针所指的值 pc=dfasdfa;/错误,不能
32、改变指针本身错误,不能改变指针本身2.13.22.13.2内联(内联(inlineinline)函数)函数u在执行程序过程中如果要进行函数调用,则系统要在执行程序过程中如果要进行函数调用,则系统要将程序当前的一些状态信息存到栈中,之后进行将程序当前的一些状态信息存到栈中,之后进行,同时转到函数的代码处去执行函数体语句,这些参数保存同时转到函数的代码处去执行函数体语句,这些参数保存与传递的过程中需要时间和空间的开销,使得程序执行效与传递的过程中需要时间和空间的开销,使得程序执行效率降低,特别是在程序率降低,特别是在程序以及函数代码以及函数代码段比较少时,这个问题会变得更为严重。为了解决这个问段比
33、较少时,这个问题会变得更为严重。为了解决这个问题,题,C+C+引入了内联函数机制。引入了内联函数机制。u使用内联函数是一种用使用内联函数是一种用的措施,若内联的措施,若内联函数较长,且调用太频繁时,程序将加长很多。因此,通函数较长,且调用太频繁时,程序将加长很多。因此,通常常,对于较长的函数最,对于较长的函数最好作为一般函数处理。好作为一般函数处理。2.13.22.13.2内联(内联(inlineinline)函数)函数一般情况下,我们对内联函数做如下的一般情况下,我们对内联函数做如下的限制:限制:(1)(1)不能有递归不能有递归(2)(2)不能包含静态数据不能包含静态数据(3)(3)不能包含
34、循环不能包含循环(4)(4)不能包含不能包含switchswitch和和gotogoto语句语句(5)(5)不能包含数组不能包含数组若一个内联函数定义不满足以上限制,则编译系统若一个内联函数定义不满足以上限制,则编译系统把它当作普通函数对待。把它当作普通函数对待。【例例2.112.11】内联函数的使用。内联函数的使用。332.13.32.13.3带默认参数的函数带默认参数的函数如果在函数说明或函数定义中为形参指定一个默认值,如果在函数说明或函数定义中为形参指定一个默认值,则称此函数为带默认参数的函数则称此函数为带默认参数的函数。当函数调用发生后,在当函数调用发生后,在形参表中等号后的各形参表中
35、等号后的各“默认值默认值”将起实参的传递作用。将起实参的传递作用。void fun(int a,int b=1,int c=4,int d=5);如果函数有多个默认参数,则默认参数必须是如果函数有多个默认参数,则默认参数必须是定义,并且在一个默认参数的右边不能有未指定默认值定义,并且在一个默认参数的右边不能有未指定默认值的参数。的参数。void fun(int a=3,int b=6,int c,int d);void fun(int a=65,int b=3,int c,int d=3);需要需要特别注意特别注意的是如果在函数原型的声明中设置了函的是如果在函数原型的声明中设置了函数参数的默认
36、值,则不可再在函数定义的头部重复设置,数参数的默认值,则不可再在函数定义的头部重复设置,否则编译时将出现错误信息。否则编译时将出现错误信息。void fun(int,int=1,int=4,int=5);35思考下列关于设置缺省参数值的描述中,错误的是()。可对函数的部分参数或全部参数设置缺省值在有函数原型时,缺省值应该设置在函数原型中,而不是函数定义时设置函数缺省参数值时,只可用常量,不可用含有变量的表达式设置函数参数默认值应从右向左设置ABCD提交单选题1分2.13.42.13.4函数重载(函数重载(overloadoverload)C+C+编译系统允许为两个或两个以上的函数取相编译系统允
37、许为两个或两个以上的函数取相同的函数名,但是形参的个数或者形参的类型不应相同的函数名,但是形参的个数或者形参的类型不应相同,编译系统会根据实参和形参的类型及个数的最佳同,编译系统会根据实参和形参的类型及个数的最佳匹配,自动确定调用哪一个函数,这就是所谓的匹配,自动确定调用哪一个函数,这就是所谓的函数重载函数重载无需特别声明无需特别声明,只要所定义的函数与已,只要所定义的函数与已经定义的同名函数形参形式经定义的同名函数形参形式(类型、个数类型、个数)不完全相)不完全相同,同,C+C+编译器就认为是函数的重载。编译器就认为是函数的重载。【例例2.122.12】重载函数应用举例重载函数应用举例 3
38、6 不可以定义两个具有相同名称、相同参数类型和不可以定义两个具有相同名称、相同参数类型和相同参数个数,只是函数返回值不同的函数。相同参数个数,只是函数返回值不同的函数。int func(int x);float func(int x);如果某个函数参数有缺省值,必须保证其参数缺如果某个函数参数有缺省值,必须保证其参数缺省后调用形式不与其它函数混淆。省后调用形式不与其它函数混淆。int f(int a,float b);void f(int a,float b,int c=0);函数调用语句:函数调用语句:f(10,2.0);具有二义性,既可以调具有二义性,既可以调用第一个函数,也可以调用第二个
39、函数,编译器不能根据用第一个函数,也可以调用第二个函数,编译器不能根据参数的形式确定到底调用哪一个。参数的形式确定到底调用哪一个。【例1】下列选择重载函数的不同实现的判断条件中,错误的是()。参数类型不同参数个数不同参数顺序不同函数返回值不同ABCD提交单选题1分2.13.5 2.13.5 函数模板(函数模板(function templatefunction template)u模板是一种使用模板是一种使用无类型参数无类型参数来产生一系列函数或类来产生一系列函数或类的机制。模板是以一种完全通用的方法来设计函数和类,的机制。模板是以一种完全通用的方法来设计函数和类,而不必预先说明将被使用的每个
40、对象的数据类型。通过模而不必预先说明将被使用的每个对象的数据类型。通过模板可以产生类或函数的集合,使它们操作不同的数据类型,板可以产生类或函数的集合,使它们操作不同的数据类型,从而避免为每一种数据类型产生一个单独的类或函数。从而避免为每一种数据类型产生一个单独的类或函数。uC+C+提供的提供的函数模板函数模板可以定义一个对任何类型变量可以定义一个对任何类型变量进行操作的函数,从而进行操作的函数,从而增强了函数设计的通用性增强了函数设计的通用性。这。这是因为普通函数只能传递变量参数,而函数模板提供了传是因为普通函数只能传递变量参数,而函数模板提供了传递类型的机制。递类型的机制。函数模板的一般说明
41、形式如下:函数模板的一般说明形式如下:template (函数模板形参表函数模板形参表)/函数定义体函数定义体 2.13.5 2.13.5 函数模板(函数模板(function templatefunction template)尖括号中不能为空,参数可以有多个,用尖括号中不能为空,参数可以有多个,用逗号分开。模板参数主要是模板类型参数。模板类型参数逗号分开。模板参数主要是模板类型参数。模板类型参数代表一种类型,由关键字代表一种类型,由关键字 classclass 或或 typenametypename后加一个标识符后加一个标识符构成,它们表示后面的参数名代表一个基本数据类型或用构成,它们表示
42、后面的参数名代表一个基本数据类型或用户定义的类型。户定义的类型。模板声明语句必须置模板声明语句必须置于与其相关的函数声于与其相关的函数声明或定义语句之前明或定义语句之前 template T “T T”可以在程序运行时被任何可以在程序运行时被任何C+C+语言支持的数据类型语言支持的数据类型所取代。如有两个以上的模板参数时,使用逗号分隔,所取代。如有两个以上的模板参数时,使用逗号分隔,template T2 函数模板定义不是一个实实在在的函数函数模板定义不是一个实实在在的函数,编译系统不,编译系统不为其产生任何执行代码。该定义只是对函数的描述,表示为其产生任何执行代码。该定义只是对函数的描述,表
43、示它每次能单独处理在类型形式参数表中说明的数据类型。它每次能单独处理在类型形式参数表中说明的数据类型。【例例2.132.13】编写一个对具有编写一个对具有n n个元素的数组个元素的数组aa求最小值的求最小值的程序,将求最小值的函数设计成函数模板。程序,将求最小值的函数设计成函数模板。2.13.5 2.13.5 函数模板(函数模板(function templatefunction template)3 8 当模板函数与重载函数同时出现在一个程当模板函数与重载函数同时出现在一个程序体内时,序体内时,C+C+编译器的求解次序是编译器的求解次序是;如果不匹配,则调用模板函数;如果还;如果不匹配,则调用模板函数;如果还不匹配则进行强制类型转换,前面几种方法都不匹配则进行强制类型转换,前面几种方法都不对,则最后报告出错。不对,则最后报告出错。【例例2.142.14】模板函数与重载函数。模板函数与重载函数。40