函数总结
1.简介
1.1 函数调用的过程
用对应的实参初始化函数的形参,并将控制权转移给被调用函数。主调函数的执行被挂起,被调函数开始执行。
1.2 局部变量
在函数体内定义的变量只在该函数体中才可以访问,这种变量称为局部变量,只在函数运行时才存在。
1.3 实参形参类型匹配
实参的类型必须与其对应形参的类型完全匹配:实参必须具有与形参类型相同、或者能隐式转换为形参类型的数据类型。
2. 函数返回值类型
int ,double内置类型
class类类型
void类型,不带任何返回值
复合类型(如int&或string* )
注意:在定义或声明函数时,没有显式指定返回类型是不合法的。
3. 参数传递
参数传递的真谛:
1.每次调用函数时,都会重新创建该函数所有的形参,此时所传递的实参将会初始化对应的形参。
2.形参的初始化与变量的初始化一样:如果形参具有非引用类型,则复制实参的值,如果形参为引用类型,则它只是实参的别名。
3.1 非引用形参
普通的非引用类型的参数通过复制对应的实参实现初始化。当用实参副本初始化形参时,函数并没有访问调用所传递的实参本身,因此不会修改实参的值。
非引用形参表示对应实参的局部副本。对这类形参的修改仅仅改变了局部副本的值,一旦函数执行结束,这些局部变量的值也就没有了。
3.1.1 指针形参
指针形参是指向const类型还是非const类型,将影响函数调用所使用的实参。
形参 实参
const int * constint *或者int *
int * int*
指针的初始化规则:可以将指向const对象的指针初始化为指向非const对象,
但是不能将指向非const对象的指针初始化为指向const对象。
3.1.2const形参
形参 实参
非引用的非const形参 非const实参或者const实参
int int或者const int
这种行为源于const对象的标准初始化规则。定义const对象一定要初始化,又因为初始化复制了初始化式的值,所以可用const对象初始化非const对象,反之亦然。
3.1.3 复制实参的局限性
复制实参并不是在所有的情况下都合适,不适宜复制实参的情况包括:
1.当需要在函数中修改实参的值时;
2.当需要以大型对象作为实参传递时。对实际的应用而言,复制对象所付出的时间和存储空间代价往往过大。
3.当没有办法实现对象的复制时。
对于上述几种情况,有效的解决办法是将形参定义为引用或指针类型。
3.2 引用形参
举例:
void swap(int &v1, int &v2)
{
int temp = v1;
v1 = v2;
v2 = temp;
}
swap(i, j);
形参与实参绑定:形参v1只是对象i的一个别名,形参v2只是对象j的一个别名。对v1的任何修改实际上也是对i的修改,同样地,对v2的任何修改实际上也是对j的修改。
3.2.1 使用引用形参返回额外的信息
函数只能返回单个值,但有些时候,函数有不止一个的内容需要返回。
这时候,可以额外定义一个引用形参,用户返回需要的内容。
3.2.2 利用const引用避免复制
对于大部分类类型或者大型数组,复制实参的效率太低了,而且某些类类型是无法复制的。
使用引用形参,函数可以直接访问实参对象,而无需复制它。
引用& 避免了复制,而直接访问对象本身
const 避免了对实参本身的修改
const & 既避免复制,又不对实参进行修改
3.2.3 更灵活的指向const的引用
应该将不需要修改的引用形参定义为const引用。普通的非const引用形参在使用时不太灵活。这样的形参既不能用const对象初始化,也不能用字面值或产生右值的表达式实参初始化。
3.2.4 传递指向指针的引用
举例:
int *&v1
从右至左理解:v1是一个引用,与指向int型对象的指针相关联。也就是说,v1只是传递进ptrswap函数的任意指针的别名。
3.3 vector和其他容器类型的形参
C++程序员倾向于通过传递指向容器中需要处理的元素的迭代器来传递容器。
举例:
void print(vector<int>::const_iterator beg,
vector<int>::const_iteratorend)
3.4 数组形参
3.4.1通过指针传递数组
因为数组不能复制,所以无法编写使用数组类型形参的函数。因为数组会被自动转化为指针,所以处理数组的函数通常操纵指向数组中的元素的指针来处理数组。
void printValues(int*)
void printValues(int[])
void printValues(int[10])
这三种定义是等价的,形参类型都是int *
通常,将数组形参直接定义为指针要比使用数组语法定义更好。这样就明确地表示,函数操纵的是指向数组元素的指针,而不是数组本身。由于忽略了数组长度,形参定义中如果包含了数组长度则特别容易引起误解。
3.4.2 通过引用传递数组
如果形参是数组的引用,编译器不会将数组实参转化为指针,而是传递数组的引用本身。在这种情况下,编译器会检查数组实参的大小与形参的大小是否匹配。
3.5 可变形参
在无法列举出传递给函数的所有实参的类型和数目时,可以使用省略符形参。省略符暂停了类型检查机制。它们的出现告知编译器,当调用函数时,可以有0或者多个实参,而实参的类型未知。
void foo(parm_list,…);
void foo(…);