首先是C++的函数与C基本一致的地方:
-
函数定义(同C)
函数是定义好的、可重用的功能模块。
定义函数是将一个模块的算法用C++描述出来。
函数名是功能模块的名字。
函数的参数是计算所需要的数据和条件。
函数的返回值:需要返回的计算结果。
-
函数定义的语法形式(同C)
函数名
形式参数表
语句序列
类型标识符
-
函数调用(同C)
调用函数需要先声明函数原型。
函数的定义在调用之前,则可以不用声明函数原型,若在调用之后,则必须在调用函数前声明函数原型。
函数原型:类型标识符 被调用的函数名 (含类型说明的形参表)
函数调用的形式:函数名(实参列表)
函数的嵌套调用:指在一个函数的函数体中,调用另一函数。
函数的递归调用:函数直接或间接的调用自身,称为递归调用。
-
函数的参数传递(同C)
值传递
下面是C++从C扩展的内容:
-
引用
引用可以作为双向传递。
引用(&)是标识符的别名,例如:
int i, j;
int &ri = i; //定义int引用ri,并初始化为变量i的引用。
定义一个引用时,必须同时对它进行初始化,使它指向一个已存在的对象。
j = 10;
ri = j; //相当于i = j;
定义一个引用后,这个引用就只能指向这个变量而不能改变指向。
引用可以作为形参。
-
含有可变参数的函数
实现一个可变长度的形参表。
C++标准中提供了两种主要的方法:
1、如果所有的实参类型相同,可以传递一个名为initializer_list的标准库类型;
2、如果实参的类型不同,我们可以编写可变参数的模板(之后介绍)
initislizer_list是一种标准库模板,用于表示某种特定类型的值的数组,该类型定义在同名的头文件中。
initislizer_list的使用方法:
initislizer_list是一个类模板,使用模板时,我们需要在模板名字后面跟一对尖括号,括号内给出类型参数。
例如:initislizer_list<string> ls; //initislizer_list的元素类型是string
initislizer_list<int> li; //initislizer_list的元素类型是int
initislizer_list比较特殊的一点是,其对象中的元素永远是常量值,我们无法改变initislizer_list对象中元素的值。
含有initislizer_list形参的函数也可以同时拥有其他形参。
-
内联函数
用来实现一种不太复杂的功能,并且要加快执行速度时选用内联函数。
声明时使用关键字inline
编译时在调用处用函数体进行替换,节省了参数传递、控制转移等开销。
注意:内联函数体内不能有循环语句和switch语句;
内联函数的定义必须出现在内联函数第一次被调用之前;
对内联函数不能进行异常接口声明。
-
constexpr函数
语法规定:constexpr修饰的函数在其所有参数都是constexpr时,一定返回constexpr。
函数体中必须有且只有一条return语句。
例如:
constexpr int get_size() {return 20;}
constexpr int foo = get_size(); //正确,foo是一个常量表达式
-
带默认参数值的函数
可以预先设置默认的参数值,调用时如给出实参,则采用实参值,否则采用预先设置的默认参数值。
注意:有默认参数的形参必须列在形参列表的最右,即默认参数值的右面不能有无默认值的参数。
调用时实参与形参的结合次序是从左向右。
例如:
int add(int x, int y = 5, int z = 6);//正确
int add(int x = 1, int y = 5, int z);//错误
int add(int x = 1, int y, int z = 6);//错误
默认参数值与函数的调用位置:
如果一个函数有原型声明,且原型声明在定义之前,则默认参数值应在函数原型声明中给出;
如果只有函数的定义,或函数定义在前,则默认参数值可以函数定义中给出。
-
函数重载
C++允许功能相近的函数在相同的作用域内以相同的函数名声明,从而形成重载,方便使用,便于记忆。
重载函数的形参必须不同,个数不同或类型不同。
编译程序将根据实参和形参的类型及个数的最佳匹配来选择调用哪一个函数。
不要讲不同功能的函数声明为重载函数,以免出现调用结果的误解、混淆。如: