6.2.1 传值函数
【熟悉C 的程序员常常使用指针类型的形参访问函数外部的对象。在C++ 语言中,建议使用引用类型的形参替代指针。】
6.2.2 传引用函数
【正如在学习引用时介绍过的,使用引用可以避免拷贝以节省时间和空间。甚至有的类型根本不支持拷贝。
同样,当函数无需修改引用形参的值时最好使用常量引用,其性能要由于使用值传递的普通形参。】
【使用引用形参返回额外信息:
一个函数只能返回一个值,然而有时函数需要同时返回多个值。引用形参为我们一次返回多个结果提供了有效的途径。(
定义一个新的数据类型也是一种可行的方法,即面向对象的编程方法)
但是这种返回多个值的方法接口比较模糊,需要我们在被调函数之外另设其他变量(某些功能的一部分是在该函数之外完成的),函数本身的移植性较差。】
6.2.3 const 形参和实参
【如之前const 部分所述,当用实参初始化形参时,实参的顶层const 并不会被复制到形参上。】
【
尽量使用常量引用:
把函数不会改变的形参定义成(普通的)引用是一种常见的错误,这么做带给函数的调用者一种误导,即函数可以修改它的实参的值;
使用引用而非常量引用也会极大地限制函数所能接受的实参类型。】
6.2.4 数组形参
【数组的两个特殊性质对我们定义和使用作用在数组上的函数有影响,这两个性质分别是:
不允许拷贝数组以及
使用数组时会将其转换成指针。】
【尽管不能以值传递的方式传递数组,但是我们可以把形参写成类似数组的形式:
// 以下三个函数是等价的,都有一个const int* 类型的形参,接受的实参的值在函数中被当成指向数组头元素的指针使用
void print(const int*)
void print(const int[])
void print(const int[10]) // 这里的维度仅有提示意义,实际传入的指针指向的数组不一定长度为10,甚至指针指向的不一定为数组
函数仅仅检查传入的参数是否为const int*,对是否指向数组不关注以及指向什么样的数组不加检查。】
【因为数组是以指针的形式传入的,所以一开始函数并不知道数组的确切尺寸,调用者应该为此提供一些额外信息。
管理指针形参有三种常用的技术:
使用标记制定数组长度-----适用于那些有明显结束标记且该标记不会与普通数据混淆的情况(C 风格字符串);
使用标准库规范-----传递指向数组首元素和尾后元素的指针两个参数;
显式传递一个表示数组大小的形参-----定义一个size 类型的形参表明数组的大小。】
【传递多维数组:
当将多维数组传递给函数时,真正传递的是指向数组首元素的指针,即指向某一数组的指针。
函数同样只检查传入的参数是否为指向该种数组类型的指针,不检查指向的是否是这种数组的数组。
void print(int (*a)[10]) // 括号一定要加,包括下面的数组引用形参,引用也要和名称括在一起
void print(int a[][10]) // 第一个维度没有语法意义
void print(int a[10][10]) // 三种等价的定义
第二个维度及之后的所有维度都是数组类型的一部分,有语法意义,不能忽略且必须准确。】
【数组引用形参:
C++ 语言允许将变量定义成数组的引用,同样,形参也可以是数组的引用。(实际上传递指向数组首元素的指针已经可以实现访问外部并修改外部元素的功能了)
在使用数组引用形参时,数组的维度作为数组的类型具有语法意义,这是与传递指针的方式不同的。也因此限制了函数的可用性,因为函数只能用于固定大小的数组。
16.1.1 节将介绍如何给引用类型的形参传递任意大小的数组。】
6.2.5 main: 处理命令行选项
【操作台运行环境下给main 函数提供实参的方法。】
6.2.6 含有可变形参的函数
【有时我们无法提前预知应该向函数传递几个参数。例如,我们想要编写代码输出程序产生的错误信息,此时最好用同一个函数实现该功能,以便对所有错误的处理能够整齐划一。然而不同的错误信息可能对应着不同数量的实参。
为了编写能处理不同数量实参的函数,
C++11 新标准提供了两种主要的方法:
如果所有的实参类型相同,可以传递一个名为initializer_list 的标准库类型;
如果实参的类型不同,我们可以使用可变参数模板,在16.4节介绍。
C++ 还有一种特殊的形参类型(省略符),可以用它传递可变数量的实参。这种功能一般只用于与C 函数交互的接口程序。】
【
initializer_list 形参(vector 在逻辑上可以实现与其同样的功能,只是重载时可能出错,而且性能不及前者):
如果函数的某些实参数量未知但是全部实参的类型都相同,我们可以使用initializer_list 类型的形参,其定义在同名的头文件中。
initializer_list<T> lst; // 默认初始化;T 类型元素的空列表
initializer_list<T> lst{a, b, c, ...} // lst 的元素是对应初始值的副本;列表中的元素是const
lst2(lst) // 拷贝或赋值一个initializer_list 对象不会拷贝列表中的元素;拷贝后两者共享元素(基于这种类型具有顶层const 的特点)
lst.size() // 列表中的元素数量
lst.begin() // 返回首指针
lst.end() // 返回尾后指针
initializer_list 是一种模板类型,
该类型对象中的元素永远是常量值,我们无法改变initializer_list 对象中元素的值。
向initializer_list 形参传递一个值的序列时,传递一个放在花括号里的序列(如vector 对象的初始化)。】
【省略符形参:
省略符形参是为了便于C++ 程序访问某些特殊的C 代码(使用了varargs 的C 标准库功能)而设置的,通常不用于其他目的。
省略符形参只能出现在形参列表的最后一个位置,省略符形参所对应的实参无须类型检查。】