Skip to main content

第 6 章:函数

6.1 函数基础

一个函数(Function)包括:返回类型(return type)、函数名、由 0 个或多个形参(parameter)形成的列表以及函数体。

通过调用运算符(call operator)来执行函数。

形参和实参

实惨是形参的初始值。

函数的形参列表

空的形参列表可以如下,隐式定义或显式定义

void f1() {}
void f2(void) {}

函数的返回类型

一种特殊的返回类型是 void,表示不返回任何值。

6.1.1 局部对象

名字有作用域、对象有生命周期(lifetime)

形参和函数体内部定义的变量统称为局部变量(local variable)

自动对象

函数开始时申请存储空间,函数结束后自动对象的值变成未定义。

形参是一种自动对象。

局部静态对象

令局部变量的生命周期贯穿函数调用以及之后的时间。

static int i = 0;

6.1.2 函数声明

函数的三要素(返回类型、函数名、形参类型)描述了函数的接口,说明了调用该函数所需的全部信息。函数声明也称作函数原型(function prototype)。

void print (int a, int b);

含有函数声明的头文件应该被包含到定义函数的源文件中。

6.2 参数传递

形参初始化的机理与变量初始化一样。

形参是引用类型:实参被引用传递(passed by reference),函数被引用调用(called by reference)。

当实参的值被拷贝给形参时,形参和实参是两个相互独立的对象:实参被值传递(passed by value),函数被传值调用(called by value)。

传值参数

✨在 C++ 语言中,建议使用引用类型的形参替代指针。

void fn (int *ip);

fn(&iv);

传引用参数

void fn (int &ir);

fn(iv);

使用引用避免拷贝。

✨如果函数无须改变引用形参的值,最好将其声明为常量引用。

使用引用形参“返回”额外信息

实际是通过改变引用形参,来达到目的。

const 形参和实参

尽量使用常量引用

数组形参

main:处理命令行选项

int main (int argc, char *argv[]) {}
int main (int argc, char **argv) {}

当执行 prog -d -o file

argv[0] ---- prog

argv[1] ---- -d

argv[2] ---- -0

argv[3] ---- file

如上,从 argv[1] 开始拿参数,argv[0] 为程序名。

含有可变形参的函数

有时候无法提前预知应该向函数传递几个实参。

initializer_list

也是一种模版类型,它的元素永远都是常量。

error_msg({ "functionX", "some error" })

省略符形参

这种方式是为了 c++ 程序访问某些特殊 c 代码。

省略符形参应该仅仅用于 C 和 C++ 通用的类型

省略符形参所对应的实参无须类型检查

void foo(parm_list, ...);
void foo(...);

6.3 返回类型和 return 语句

return;

return expression;

无返回值函数

在返回类型是 void 的函数中使用无返回值函数。会在最后隐式的 return。

有返回值函数

只要返回类型不是 void 的函数,都必须 return 对应类型的值。

不要返回局部对象的引用或指针。

函数结束时临时对象的占用空间会被释放掉,return 语句将会指向不再可用的内存空间。

主函数 mian 的返回值

mian 函数的返回值可以看作是状态指示器。返回 0 表示成功,返回其他表示失败。

返回数组指针

因为数组不能被拷贝,所以函数不能返回数组。可以返回数组的指针或引用。

Type (*function (parameter_list))[dimension];

Type 表示元素的类型,dimension 表示数组的大小。

int (*func(int i))[10];

使用尾置返回类型

auto func(int i) -> int(*)[10]

6.4 函数重载

mian 函数不能重载。

最好只重载那些非常相似的操作。

调用匹配的重载函数的过程叫函数匹配(重载确定)

匹配结果:最佳匹配、无匹配、匹配到太多的(二义性调用)。

重载与作用域

如果在内层作用域中声明名字,将会隐藏外层作用域中的同名实体。

6.5 特殊用途语言特性

默认实参

string screen(int a = 10, char b = '');

通常,应该在函数声明中指定默认实参,并将该声明放在合适的头文件中。

内联函数和 constexpr 函数

内联函数可以避免函数开销的调用

在编译过程中 shorterString("xx", "xx") 会被展开成他的函数内容。

一般来说,内联机制用于优化规模较小、流程直接、频繁调用的函数。

inline const string shorterString(const string &str1, const string &str2);

constexpr 函数

函数的返回类型以及所有形参都必须是字面值类型。函数体只有一条 return 语句。

constexpr 函数不一定返回常量表达式。

constexpr int new_sz() { return 42; }

调试帮助

assert(expr);

_ FILE _ 存放文件名的字符串字面值。

_ LINE _ 存放当前行号的整型字面值。

_ TIME _ 存放文件编译时间的字符串字面值。

_ DATE _ 存放文件编译日期的字符串字面值。

6.6 函数匹配

候选函数

  • 与被调用的函数同名

  • 声明在调用点可见

可行函数

  • 形参数量和提供实参数量相等

  • 类型一一相等,或能转换

实参类型转换

  1. 精确匹配
  2. 通过 const 转换实现
  3. 通过类型提升实现
  4. 通过算数类型转换
  5. 通过类型转换

6.7 函数指针

函数指针指向函数,而非对象。

pf 是一个指针指向一个函数。

bool (*pf) (const int &);

pf 是一个函数,返回 bool * 类型。

bool *pf (const int &);