1. 为什么需要函数
- 可将应用程序的内容划分成依次调用的逻辑块,让您能够划分和组织程序的执行逻辑,有助于提高可重用性。
2. 基本概念
- 是子程序,可接受参数,可有返回值。
- 要让函数执行其任务,必须调用它。
- 函数原型/声明
- 指出函数的名称(Area)、接受的参数列表以及返回值类型。
- 让编译器意识到这些语句是合法的,而链接器负责将函数调用与实现关联起来,并确保程序执行时将触发它们。
- 函数定义
- 函数调用、形参、实参
- 函数声明中包含的参数列表中的参数是形参(parameter),形参类似于局部变量,旨在当前函数内部可用
- 调用函数时(必须)提供的参数列表中的参数是实参(argument),它们是函数的形参列表要求的值
- 带默认值的函数参数
- 相当于是可选参数,用户可以传实参,也可以不传
- 不管有几个,必须在形参列表结尾
- 可被用户提供的值覆盖
- 返回值
- 除非返回类型声明为void,否则至少包含一条return语句(有些程序员喜欢仍然返回一条空的return语句:return;)
- 也可以由多条return语句,但要谨慎,比在末尾返回的函数难理解。
- 递归函数
- 调用自己
- 必须有明确的退出条件
- 如果没有退出条件或存在bug,有可能一直调用自己,直到栈溢出后才终止,导致应用程序崩溃
3. 使用函数处理不同类型的数据
- 函数重载
- 传递数组参数
- 如果传数组参数,最好把长度也传上,方便函数内进行判断
- 使用字符数组时,最好把最后一个初始化为'\0'
- 按引用传递参数
- void Area (double radius, double& result)
- &告诉编译器,不要将第二个实参复制给函数,而将指向该实参的引用传递给函数。
- 使用return时函数只能返回一个值,因此如果函数需要执行影响众多值的操作,且需要在调用者中使用这些值,则按引用传递参数时让函数将修改结果提供给调用模块的方式之一。
4. 微处理器如何处理函数
- 调用逻辑
- 使用一个栈存储函数调用开始时的位置,然后再进入子函数体中,接着在遇到return时才从栈中找出原地址,并返回继续执行外层代码。
- 编译器使用CALL(函数调用)和RET(类似return)指令
- 编译器有许多优化选项,优化代码大小时,可能会护忽略众多的内联请求;优化速度时,编译器通常会寻找并利用合理的内联机会。
- 内联函数
- 函数很简单并需要降低开销(调用函数反而比函数逻辑复杂时)时才使用,不然每个调用的地方都会拷一份相当的函数定义代码,导致代码急速膨胀
- 参考
- 自动推断返回类型
- 与auto类型的变量类似,函数必须先定义,并且每个return的返回类型都要相同,不然编译器难以判断
- lambda函数
- C++11引入的,有助于使用STL算法对数据进行排序或处理
- 作为谓词使用,简化了排序函数、foreach等需要的复杂的二元谓词(是这样一个函数,对两个参数进行比较,并返回true或false,通常被实现为类中的运算符)的定义