一、基础概念
- 调用函数: 主调函数的执行被暂时中断,控制权转移给被调函数,被调函数开始执行。
-
执行函数:
1.(隐式地)定义并初始化(注意: 不是赋值)函数形参;实参是形参的 初始值 。- 遇到 return 语句时结束执行,返回 return 语句中的值,并将控制权转移回主调函数。
- 函数声明: 和变量名一样,函数名字在使用前也需要先声明。类似于变量,函数只能定义一次,但可以声明多次。建议在头文件中声明函数,在源文件中定义函数;而且定义函数的源文件应该包含声明函数的头文件,编译器负责检验函数的定义和声明是否匹配。
二、传参
1、值传递
形参不是引用类型时,进行值传递。实参的值被拷贝给形参,形参和实参是两个独立的对象。函数对形参的所有操作都不会影响实参。
2、引用传递
形参是引用类型时,它将绑定到对应的实参上。此时形参是实参的别名,函数对形参的操作都会反映在实参上。
当实参是较大的类类型对象或容器对象时,直接拷贝实参给形参比较低效,甚至有些类类型根本就不支持拷贝操作。此时函数就可以使用引用形参来访问实参。
引用传递时,函数的形参最好定义为 常量引用 。一方面,它暗示了函数不会修改实参的值;另一方面,非常量引用作为形参,会极大地限制函数所能接受的实参类型,比如 const 对象、字面值或需要类型转换的对象就不能传递给形参。
3、数组形参
数组的2个特殊性质:(1) 不允许拷贝数组;(2)使用数组时,通常会将其转换成指针。
由于数组的特殊性质,我们无法以值传递的方式使用数组参数;而且,当我们向函数传递一个数组参数时,实际上传递的是指向数组首元素的指针 。
因为数组是以指针的形式传递给函数的,所以函数并不知道数组的确切大小。因此,调用者应该提供一些额外的信息来让函数确定数组的大小。一般有以下3中方式:
- 数组本身包含一个结束标记,如C风格字符串
- 传给函数数组首元素和尾后元素的指针(使用标准库中的
begin
、end
函数) - 显式传递一个表示数组大小的形参
还可以将数组形参定义为数组的引用,此时,引用形参绑定到对应的数组实参上:
void func(int (&array)[10]) {
...
}
这种方式下,数组的大小是确定的,只能传给函数一个维度为10的数组
三、返回
- 返回类型是
void
的函数表示函数没有返回值,直接使用return;
语句即可。 - 返回一个值的方式和初始化一个变量或形参的方式完全一样: 返回的值用于初始化调用点的一个 临时量 ,该临时量就是函数调用的结果。
- 不要返回 局部 对象的引用或指针:函数调用完成后,所占用的内存空间也随之被释放,因此,函数完成意味着函数中的 局部变量 的引用或指针将指向不再有效的内存区域。
四、函数重载
函数重载: 同一作用域内多个函数名字相同但形参列表不同
-
重载 和 顶层const形参: 一个拥有顶层const的形参和另一个没有顶层const的形参无法区别开,比如:
当调用函数fun时,程序无法确定调用的是哪个版本。// 声明函数 void fun(const int num); void fun(int num); // 调用函数 fun(2);
五、函数指针
函数指针指向函数而非对象。函数指针指向某种特定类型,函数的类型由它的返回类型和形参类型共同决定 ,与函数名无关。
bool lengthCompare(const string &, const string &);
该函数的类型是 bool(const string &, const string &)。声明一个指向该函数的指针,只需要用指针替换函数名即可:
bool (*pf)(const string &, const string &);
5.1 使用函数指针
当把函数名作为一个值使用时,该函数名自动转换成指针。
pf = lengthCompare; //pf指向lengthCompare函数
pf = &lengthCompare; //等价,取地址符是可选的
也可以直接使用函数指针来调用函数:
bool b1 = pf("hello", "world"); //不必先解引用
bool b2 = (*pf)("hello", "world"); //等价调用,可以先解引用指针
bool b3 = lengthCompare("hello", "world"); //和上面两个调用是等价的
5.2 形参是函数指针
无法定义函数类型的形参,但形参可以是指向函数的指针:
// 两个等价的函数声明
void func(bool pf(const string &, const string &));
void func(bool (*pf)(const string &, const string &));
// 可以把函数作为实参使用,传入函数名,自动转换成指针
func(lengthCompare);
5.3 return 函数指针
和数组类似,虽然不能返回一个函数,但是可以返回指向函数的指针。此时,必须把返回类型写成指针形式。
int (*func(int)) (int*, int);
由内向外阅读这条声明语句:func有形参列表,说明func本身是一个函数,接收一个int型的参数;func前面有*
,说明func返回一个指针;这个指针的类型本身也包含一个形参列表,因此这个指针是一个函数指针,接受2个参数,返回一个int类型。