1、引用和非引用参数:
引用类型参数传的是别名,可以通过函数进行修改;非引用参数实现的是复制,不可以通过函数修改其值。
注解:非引用形参表示对应实参的局部副本,对这类行参的修改仅仅改变了局部副本的值,一旦函数执行结束,这些局部变量的值也就没有了。
引用形参:
a. 使用引用形参返回额外的信息
函数只能返回单个值,但有时候函数有不止一个的内容需要返回。这时候我们可以通过函数传递一个额外的引用实参,用于返回额外的信息。
b. 利用const引用避免复制
对于大型对象复制效率太低了,有些类型甚至无法复制,利用const引用就可以避免复制,引用形参是引用,所以不复制实参,又因为形参是const引用,所以不能使该引用
来修改实参。
c、const的灵活性
void func(int & argc){……}
short v1=0; const int v2=42; int v3;
v3=incr(0); //error, 字面值不是左值
v3=incr(v1+v2); //error, 加法不能作为左值
注意:应该将不需要修改的引用定义为const引用。普通的非const引用形参在使用时不太灵活。这样的形参既不能被const对象初始化,也不能用字面值或产生右值的表达式初始化。
2、指针形参
指针形参与其他非引用类型的行参一样,如果将新指针赋给行参,主调函数使用的实参指针的值没有改变。事实上被复制的指针只影响对指针的赋值。指针形参是const类型
还是非const类型,将影响函数调用所使用的实参。 void func(const int* argc) void func(int* const argc)
3、const类型参数
a、const绝不能用于改变非引用参数的值
—— 尽管函数的形参是const,但是编译器却将该行参声明视为普通的int型。 void fcn(const int i); void fcn(int i); 为了兼容c语言,认为这两种定义没有任何区别。
b、引用类型的参数
—— 在调用函数时,如果该函数使用非引用的非const形参,则既给该函数传递const实参也可传递非const的实参(因为改变形参不影响const的实参,所以const实参不会被
改变)。如果将形参定义为非引用的const类型,则在函数中,不可以改变实参的局部副本,由于实参是以副本的形式传递,因此传递给函数形参既可是const也可是非const对
象。 void func(const int& argc)
4、对于vector等容器类型的参数,应该传递引用&类型的形参,此样能避免非引用类型的集体复制
5、数组参数
a、数组本身作为参数传递的是数组的头指针,即函数操作的是数组元素的指针。当编译器检查数组形参关联的实参时,他只会检查实参是不是指针,指针的类型和数组元
素的类型是否匹配,而不会检查数组的长度,因此一维数组传递参数可为0长度,即void func (int arr [ ]);
注意:当不需要修改数组形参的元素时,函数应该将形参的定义为指向const对象的指针
b、如果数组作为引用类型进行传递
编译器不会将数组实参转化为指针,而是传递数组的引用本身,在这种情况下,数组的大小成为形参和实参的一部分。编译器检查数组实参的大小与形参的大小是否匹
配。
void print(int (&arr)[10]) //形参是一个数组的引用,数组的大小确定
6、如下代码
bool contains( const char ** a, const char *p);
static const char× keyword [ ] = {....}
bool iskeyword( const char*p){ return contains( keyword, p);} 编译通过
如下不能通过编译:
bool iskeyword(const char 8* const keyword, const char *p){ return contains(keywords,p ); }
正确的接口:
// 最大程度使用const
bool contains( const char* const *a , const char *p);
// 不好的做法
bool contains( const char* const* const a , const char* const p);
结论:const决不能用于改变非引用参数的值