const形参与数组形参

const形参

当形参是const时,要注意顶层const:

const int ci = 42; //不能改变ci,const是顶层的
int i = ci;      //正确,当拷贝ci时,忽略了它的顶层const
int *const p = &i;      //const是顶层的,不能给p赋值
*p = 0;          //正确,通过p改变对象的内容是允许的,现在i变成0

当使用实参初始化形参时会忽略掉顶层的econst,也就是说形参的顶层const被忽略掉。当形参是顶层const时,传给它常量对象或者非常量对象都是可以的:

void fcn(const int i) {/*fcn能够读取i,但是不能向i写值*/}

调用fcn函数时,既可以传入const inr也可以传入int。

忽略掉形参的顶层const可能产生意想不到的结果:

void fcn(const int i);
void fcn(int i);

C++语言,允许定义若干具有相同名的函数,不过前提是不同函数的形参列表应该有明显的区别。因为顶层const被忽略掉,所以在上面的代码中传入两个fcn函数的参数是完全相同的。因此,尽管形式上有差异,但是实际上第二个函数它的形参和第一个fcn的形参没有区别。

指针或引用形参与const

形参的初始化方式和变量初始化方式是一样的,可以使用非常量初始化一个底层const对象,但是反过来则不行;同时一个普通的引用必须用同类型的对象初始化。

int i = 42;
const int *cp = &i;            //正确,但是cp不能改变i
const int &r = i;         //正确,但是r不能改变i
const int &r2 = 42;           //正确
int *p = cp;          //错误,p的类型和cp的类型不匹配
int &r3 = r;         //错误,r3的类型和r的类型不匹配
int &r4 = 42;              //错误,不能用字面值初始化一个非常量引用

将同样的初始化规则应用到参数传递上可得:

int i = 0;
const int ci = i;
string::size_type ctr = 0;
reset(&i);     //调用形参类型是int*的reset函数
reset(&ci);   //错误:不能用指向const int对象的指针初始化int*
reset(i); //调用形参类型是int&的reset函数
reset(ci);      //错误,不能把普通引用绑定到const对象的ci上
reset(42);     //错误,不能把普通引用绑定到字面值上
reset(ctr);     //错误,类型不匹配,ctr是无符号类型

数组形参

数组的两个特殊性质对我们定义和使用作用在数组上的函数有影响,这两个性质分别是:不允许拷贝数组以及使用数组时会将其转换成指针。因为不能拷贝数组,所以无法以值传递的方式使用数组参数。因为数组会被转换成指针,所以为函数传递一个数组时,实际上传递的是指向数组首元素的指针。

数组形参的定义

如果要编写一个函数,输出 int 型数组的内容,可用下面三种方式指定数组形参:

// three equivalent definitions of printValues
void printValues(const int*) { /* ... */ }
void printValues(const  int[]) { /* ... */ }
void printValues(const  int[10]) { /* ... */ }

虽然不能直接传递数组,但是函数的形参可以写成数组的形式。虽然形参表示方式不同,但可将使用数组语法定义的形参看作指向数组元素类型的指针。上面的三种定义是等价的,形参类型都是const int*。

通常,将数组形参直接定义为指针要比使用数组语法定义更好。这样就明确地表示,函数操纵的是指向数组元素的指针,而不是数组本身。由于忽略了数组长度,形参定义中如果包含了数组长度则特别容易引起误解。

使用标记指定数组长度

管理数组实参的第一种方法是要求数组本身包含一个结束标记,使用这种方法的典型示例是C风格字符串,C风格字符串存储在字符数组中,并且最后一个字符后面跟着一个空字符函数在处理C风格字符串时遇到空字符停止:

void print(const char*cp)
{
       if (cp)
       while (*cp)
              cout << *cp++;
}

这种方法适用于某些有明显结束标记且该标记不会与普通数据混淆的情况,但是对于像int这样所有值都是合法值得数据就无效了。

使用标准库规范

管理数组实参的第二种技术是传递指向数组的首元素和尾后元素的指针:

void print(const int*beg, const int *end)
{
       while (beg != end)
              cout << *beg++ << endl;
}

为了调用这个函数,必须传入两个指针,一个指向要输出的首元素,另一个指向尾巴元素的下一位置。

显示传递一个表示数组大小的形参

第三种管理数组实参的方法就是专门定义一个表示数组大小的形参:

void print(const int ia[], size_t size)
{
       for (size_t i = 0; i != size; ++i)
              cout << ia[i] << endl;
}

数组形参和const

上面的三个print函数都把数组形参定义成了指向const的指针,当函数不需要对数组元素执行写操作的时候,数组形参应该指向const的指针。

数组引用形参

和其他类型一样,数组形参可声明为数组的引用。如果形参是数组的引用,编译器不会将数组实参转化为指针,而是传递数组的引用本身。在这种情况下,数组大小成为形参和实参类型的一部分。编译器检查数组的实参的大小与形参的大小是否匹配:

// ok: parameter is a reference to an array; size of array is fixed
void printValues(int (&arr)[10]) { /* ... */ }
int main()
{
int i = 0, j[2] = {0, 1};
int k[10] = {0,1,2,3,4,5,6,7,8,9};
printValues(&i); // error: argument is not an array of 10 ints
printValues(j); // error: argument is not an array of 10 ints
printValues(k); // ok: argument is an array of 10 ints
return 0;
}

这个版本的 printValues 函数只严格地接受含有 10 个 int 型数值的数组,这限制了哪些数组可以传递。然而,由于形参是引用,在函数体中依赖数组的大小是安全的:

// ok: parameter is a reference to an array; size of array is fixed
void printValues(int (&arr)[10])
{
for (size_t i = 0; i != 10; ++i) {
cout << arr[i] << endl;
}
}

&arr 两边的圆括号是必需的,因为下标操作符具有更高的优先级:

f(int &arr[10]) // error: arr is an array of references
f(int (&arr)[10]) // ok: arr is a reference to an array of 10 ints

多维数组的传递

所谓多维数组实际是指数组的数组。

和其他数组一样,多维数组以指向 0 号元素的指针方式传递。多维数组的元素本身就是数组。除了第一维以外的所有维的长度都是元素类型的一部分,必须明确指定:

// first parameter is an array whose elements are arrays of 10 ints
void printValues(int (matrix*)[10], int rowSize);

上面的语句将 matrix 声明为指向含有 10 个 int 型元素的数组的指针。

*matrix 两边的圆括号是必需的:

int *matrix[10]; // array of 10 pointers
int (*matrix)[10]; // pointer to an array of 10 ints

我们也可以用数组语法定义多维数组。与一维数组一样,编译器忽略第一维的长度,所以最好不要把它包括在形参表内:

// first parameter is an array whose elements are arrays of 10 ints
void printValues(int matrix[][10], int rowSize);

这条语句把 matrix 声明为二维数组的形式。实际上,形参是一个指针,指向数组的数组中的元素。数组中的每个元素本身就是含有 10 个 int 型对象的数组。 

posted @ 2018-05-01 23:28  刘-皇叔  阅读(2729)  评论(0编辑  收藏  举报