C++ Primer第六章函数 函数是一个命名了的代码块,我们通过调用函数执行相应的代码。函数可以有0个或多个参数,而且会产生一个结果。可以重载函数,同一个名字可以对应几个不同的函数。 函数基础定义包括以下部分:返回类型,函数名字,由0个或多个形参组成的列表以及函数体。 函数的调用完成两项工作:一是实参初始化函数对应的形参,二是将控制权转移给被调用函数。主调函数的执行被暂时中断,被调函数开始执行。 形参和实参,实参是形参的初始值,存在一一对应关系但是并没有规定实参的求值顺序。 函数的形参列表可以为空但是不能省略。 函数的返回类型不能是数组类型或函数类型但是可以是指向数组或函数的指针。 局部对象 名字有作用域,对象有生命周期 名字的作用域是程序文本的一部分,名字在其中可见 对象的声明周期是程序执行过程中该对象存在的一段时间。 自动对象 当函数的控制路径经过变量定义语句时创建该对象当到达定义所在的块末尾时销毁它。我们把只存在于块执行期间的对象为自动对象。当块执行结束后,块中创建的自动对象的值就变成未定义的了。形参是一种自动对象。 局部静态对象 在程序的执行路径第一次经过对象定义语句时初始化,并且知道程序终止才被销毁,在此期间即使对象所在的函数结束执行也不会对它有影响。 函数声明 函数只能定义一次但是可以声明多次。 因为函数的声明不包含函数体所以也就无须形参的名字。 在头文件中进行函数声明,在源文件中定义。 分离式编译 分离式编译允许我们把程序分割到几个文件中去,每个文件独立编译。 参数传递 每次调用函数时都会重新创建它的形参,并用传入的实参对形参进行初始化。 传递参数有传值和传地址(指针和引用) 传值参数 当初始化一个非引用类型的变量时,初始值被拷贝给变量。此时对变量的改动不会影响初始值。 指针形参 指针的行为和其他非引用类型一样,当执行指针拷贝操作时,拷贝的是指针的值。 使用引用避免拷贝。拷贝大的数据类型对象或者容器对象比较低效,甚至有的类不支持拷贝.函数只能通过引用形参来访问该类型对象。 使用引用形参返回额外信息 一个函数只能返回一个值,然而有时函数需要同时返回多个值。引用形参为我们一次返回多个值提供了可能。 string::size_type find_char(const string &s,char c,string::size_type &occurs) const形参和实参 当用实参初始化形参时会忽略掉顶层const。当形参有顶层const时,传给它常量对象或者非常量对象都是可以的。 在C++语言中,允许我们定义若干具有相同名字的函数,不过前提是不同函数的形参列表应该有明显区别.因为顶层const被忽略掉了,所以在上面的代码中传入的参数完全一样。 void func(const int i)和void func(int i)重定义 指针或引用形参与const 形参初始化方式和变量初始化方式是一样的。我们可以使用非常量初始化一个底层const对象但是反过来不行。同时一个普通的引用必须同类型的对象初始化。 尽量使用常引用 把函数不会改变的形参定义成常引用。 数组形参 数组的两个特殊性质对我们定义和使用作用在数组上的函数有影响,这两个性质分别是:不循序拷贝数组以及使用数组时会将其转换成指针。 因为不能拷贝数组所以我们无法以值传递的方式使用数组参数。 尽管不能以值传递的方式传递数组但是我们可以把形参协程类似数组的形式 void print(const int *) void print(const int []) void print(const int [10]) 因为数组是以指针的形式传递给函数的,所以一开始函数并不知道数组的确切尺寸,调用者应该为此提供一些额外的信息。 传递数组长度 传递首尾元素指针 数组形参和const 数组形参应该是指向const的指针.只有当函数确实要改变元素值的时候才把形参定义成指向非常量的指针。 数组引用形参 C++允许将变量定义成数组的引用,但是必须确定数组的大小 void print(int (&arr)[10]) 传递多维数组 void print(int matrix[][10],int rowSize) matrix实际上形参是指向含有10个整数的数组的指针。 main处理命令行选项 int main(int argc, char **argv) argv是一个指针数组argc是数组元素个数。 含有可变形参的函数 如果所有实参类型相同可以传递一个initializer_list如果类型不同可以传递可变参数模版。 C++还有一种特殊的形参类型(省略号)可以用它传递可变数量的实参。 initializer_list形参 和vector不一样的是,initializer_list对象中的元素永远是常量值我们无法改变。 返回类型和return语句 return语句终止当前正在执行的函数并将控制权返回到调用函数的地方。 return; return expresstion; 值是如何被返回的 返回一个值的方式和初始化一个变量或形参的方式完全一样:返回值用于初始化调用点的一个临时量,该临时量就是函数调用的结果。 不要返回局部对象的引用或指针。函数完成后它所用的存储空间也随之被释放。 返回数组指针 因为数组不能被拷贝所以函数不能返回数组。不过函数可以返回数组的指针或引用 int arr[10]; int (*p2)[10] = &arr; 返回数组指针的函数 Type (*function(parameter_list))[dimension] 函数重载 如果统一作用域内的几个函数名字相同但形参列表不同我们称之为重载函数。 调用重载的函数 函数匹配是指一个过程,在这个过程中我们把函数调用与一组重载函数中的某一个关联起来,函数匹配也叫重载确定。 编译器找到一个与实参最佳匹配的函数并生成调用该函数的代码 找不到任何一个函数与调用的实参匹配编译器就发出无匹配的错误 有一个或着多个可以匹配也发出错误二义性调用 特殊用于语言特性 默认实参,内联函数和constexpr函数。 某些函数有这样一种形参在函数的很多次调用中它们都被赋予一个相同的值,此时我们把这个反复出现的值称为函数的默认实参 内联函数和constexpr函数 内联函数就是将它在每个调用点上内联的展开。从而消除函数运行时的开销。 内联机制用于优化规模较小,流程直接,频繁调用的函数。 constexpr函数指能用于常量表达式的函数。 函数的返回类型及虽有形参类型都是字面值类型 执行初始化任务时编译器把对constexpr函数的调用替换成其结果值。为了能在编译过程中随时展开constexpr函数被隐式的指定为内联函数。 将内联函数和constexpr函数放在头文件内。 函数匹配 确定候选函数和可行函数 寻找最佳函数 含有多个形参的函数匹配 精确匹配 实参类型和形参类型相同 实参从数组类型或函数类型转换成对应的指针类型 想实参添加顶层const或者从实参中删除顶层const 通过const转换实现的匹配 通过类型提升实现的匹配 通过算术类型转换或指针转换实现的匹配 通过类类型实现的匹配 函数指针 函数指针指向的是函数而非对象。函数的类型是由它的返回类型和形参类型共通决定与函数名无关 bool (*pf)(const string &,const string &); typedef定义自己的类型 typedef bool(*FuncP)(const string&,const string&); typedef decltype(lengthCompare) *FuncP2; decltype返回函数类型并不会自动转换成函数指针所以需要加一个* using F = int(int*,int); using PF = int(*)(int*,int); F是函数类型PF是函数类型的指针 PF f1(int);//right F f1(int);//错误 F* f1(int)//正确 int(*f1(int))(int*,int); 使用auto和decltype用于函数指针类型 注意decltype获取到的是函数类型不是函数指针类型 |
|
来自: dongtongtong > 《C Primer(第五版)》