复制实参的局限性(值传递)
不适合复制实参的情况包括:
- 当需要在函数中修改实参的值时。
- 当需要以大型对象作为实参传递时。对实际的应用而言,复制对象所付出的时间和存储空间代价往往过大。
- 当没有办法实现对象的复制时。
通过引用传递数组
通常,数组以非引用类型传递,此时数组会转换为指向第一个元素的指针,形参中数组大小并没有意义。然而如果形参是数组的引用,则编译器不会将数组实参转化为指针,而是传递数组引用本身。此时数组大小会由编译器进行检查。
例:
void printValues(int (&arr)[10]){}
int main()
{
int i(0);
int j[2] = {0,1};
int k[10] = {1,2,3,4,5,6,7,8,9,0};
printValues(&i); //error
printValues(j); //error
printValues(k); //ok
return 0;
}
传递数组时何时需要指针,何时需要引用?
- 当函数需要处理数组且函数体不依赖于数组的长度时应使用指针形参,其他情况下应使用引用形参。
- 指针形参的优点是可以明确地表示函数所操纵的是指向数组元素的指针,而不是数组本身,而且可以使用任意长度的实参数组来调用函数;其缺点是函数体不能依赖于数组的长度,否则容易造成数组内存的越界访问,从而产生错误的结果或者导致程序崩溃。
- 引用形参的优点是在函数体中依赖数组的长度是安全的,其缺点是限制了可以传递的实参数组,只能使用长度匹配的实参数组来调用函数。
重载函数确定的三个步骤
考虑如下四个函数和某次调用:
void f();
void f(int);
void f(int, int);
void f(double, double = 3.14);
f(5.6); //It calls f(double, double)
- 确定候选函数:
即确定所有重载函数集合,在集合中的函数均为候选函数,本例中即为四个f函数。 选择可行函数:
即从所有候选函数中,选择一个或多个能够用本次函数调用中的实参来调用的函数。其必须满足两个条件:- 函数形参个数与调用的实参相同。
- 每个实参类型和对应形参类型相匹配,或者可被隐式类型转换为对应形参。
本例中的可行函数为:
void f(int); void f(double, double = 3.14);
寻找最佳匹配(如果有)
即在可行函数中寻找对应形参与实参最匹配的一个。
如果有且仅有一个函数满足下列条件,则匹配成功:- 该函数每个实参的匹配都不劣于其他可行函数需要的匹配。
- 该函数有一个实参匹配优于其他可行函数提供的匹配。
潜在内容:需要类型转换的匹配劣与精确匹配。
如f(5.6);
中,若调用
void f(int);
意味着有一个实参需要隐式类型转换
如调用void f(double, double = 3.14);
则每一个实参的匹配都不需要隐式类型转换。
故该函数:- 每个实参的匹配都不劣与 void f(int);。
- 第一个实参的匹配为精确匹配,优于void f(int);的第一个参数。
故最佳匹配为
void f(double, double = 3.14);
*注:若调用函数f(42,1.2);
其可行函数为:
void f(int, int); //(1)
void f(double, double = 3.14); //(2)
对于(1),其第二个实参的匹配劣于(2),对于(2),其第一个实参的匹配劣于(1)。故具有二义性,调用错误。
再*注:类型提升优于标准转换
考虑
void func(int);
void func(short);
func('a');
char->int //类型提升
char->short//类型转换
故实际调用为void func(int);
引用做形参
调用一个引用形参的函数时,传递一个右值或传递一个需要转换类型的对象是不允许的。例如:
int incr(int &val)
{
return ++val;
}
int main()
{
short v1 = 0;
const int v2 = 42;
int v3 = incr(v1); // error: v1 is not an int
v3 = incr(v2); // error: v2 is const
v3 = incr(0); // error: literals are not lvalues
v3 = incr(v1 + v2); // error: addition doesn't yield an lvalue
int v4 = incr(v3); // ok: v3 is a non const object type int
}
const做形参
令人吃(dan)惊(teng)的是,尽管函数的形参是const,但是编译器却将func的定义视为其形参被声明为普通的int型:
void func(const int i)
{
cout << i << endl;
}
void func(int i)
{
cout << i << endl;
}
error C2084: 函数“void func(const int)”已有主体
这种用法是为了支持对C语言的兼容,因为在C语言中,具有const形参或非const形参的函数并无区别。
杂记
int *&v1;
这个应该从右至左理解,V1是一个引用,和一个int*的类型绑定。
只能为一个形参指定默认实参一次。
每一个版本的重载函数应该声明在同一个作用域。
函数指针只能通过同类型的函数或函数指针或0值常量进行初始化或赋值。
直接引用函数名等效于在函数名上应用取地址操作符。
指向重载函数的指针必须与重载函数的一个版本精确匹配。
- C++中以多维数组为形参的函数必须指明除第一维以外的其他维,例如:
printValues(int (*matrix)[10], int rowSize);