C++ Primier读后感 之 第七章 函数

第七章:函数

1. const类型函数参数

当一个函数的参数为const的引用或指针类型时,在函数的作用域中必须保证参数不改变:

extern fun1(int &);

void fun(const int & xx)

{

fun1(xx);     错误,无法保证在fun1xx不被改变

}

上面的错误有三种修改方案:

(1) extern fun1(int);     fun1的参数声明为按值传递,这样可以保证fun中的xx的值不被改变。

(2) extern fun1(const int &);     fun1的参数声明为传递常引用,这样也可以保证xx不被修改。

(3) int x = xx; fun1(x);     定义一个临时变量,拷贝xx的值,这样fun1修改的就是临时变量的值。

上面三中修改方案都是可以接受的。

 

2. 参数类型的选择

默认情况下位引用和指针参数都是按值传递。一般通过以下准则来选择参数传递类型:

(1) 对于基本数据类型,且不需要在函数中改变实参值,推荐使用值传递。

(2) 引用变量一旦定义就必须用一个有效的对象初始化,它不允许引用一个空值。指针参数可以指向空地址。所以在函数调用时,如果实参可能为空,就不能选引用传递了而必须用指针传递了。

注意:由于指针的这一特性,所以在函数中使用指针之前,必须判断指针所指对象是否有效,因为对一个空地址进行解引用是非法的。使用引用参数就可以直接使用,而无需判断对象是否有效,这个工作由调用时完成。

(3) 引用一旦初始化,就不能在引用其他的对象了,因此如果在函数中需要形参指向其他位置或引用其他对象,就必须使用指针传递了。

(4) 引用的效率和指针相同,它比指针的好处是在使用中和变量保持一致,所以在不涉及到上面两点的情况下,一般推荐使用引用传递参数。

(5) 如果一个函数中不需要改变实参的值,建议将行参声明为const类型。(值传递就无所谓了,因为值传递本身就不改变实参的值。)

 

3. 一维数组参数

数组作为参数,它传递的是数组第一个元素的指针。编译器不检查数组的大小,只检查其类型。

void putvalue(int *);     声明了一个参数为int指针的函数

void putvalue(int []);     声明了一个参数为int指针的函数

void putvalue(int [10]);     声明了一个参数为int指针的函数

上面三种函数声明的含义是一致,调用函数时,编译器只检查参数是否为int*,其它的不检查。

int i, j[2];

putvalue(&i);     正确,但是在函数中会隐含错误,数组极可能越界

putvalue(j);     正确,但是还是无法保证数组是否越界

为了解决数组越界的问题,先有三种处理方式:

(1) 在数组参数后面加上一个数组长度的参数,在函数用此参数类限制数组长度。上面的函数声明换成:

void putvalue(int[], int size);

int i, j[2];

putvalue(&i, 1);     在函数中限制访问i的长度为1,就不会越界

putvalue(j, 2);     在函数中限制访问j的长度为2,就不会越界

这中方式是C程序设计中贯用的一种方法。

(2) 将参数数组声明为数组的引用。数组的引用包含数组的长度,编译器会检查数组参数的长度。

void putvalue(int (&array)[10]);

定义中array是一个包含10个元素的的一维数组的引用。在函数调用中,实参必须是一个包含10个元素的一维数组才能正确调用。

putvalue(&i);     错误,实参长度不为10

putvalue(j);     错误,实参长度不为10

注意:

int &array[10]     含义是定义了一个一维数组array,数组中的元素时整形引用。这个定义是错误的,C++中不允许定义引用数组。

int (&array)[10]     含义是array是一个引用,引用的类型是int[10],即array引用一个包含10个元素的一维数组。

(3) 使用容器作为参数

标准C++中,容器是可以随时取得自身长度的,所以可以在函数中进行限制。

 

4. 多维数组参数

多维数组参数必须指明除第一维外的所有维的长度,在传参时,编译器只检查除

第一维外的所有维的长度是否匹配。

void putvalue(int (*array)[10]);

void putvalue(int array[][10]);

void putvalue(int array[20][10]);

上面三种声明是一致的,调用时,编译器只会检查实参是否是int (*array)[10]类型的,只要

求实参的第二位长度为10,对第一维的长度不作限制。

注意:

int *array[10]     含义是定义了一个包含10int型指针的一维数组array

int (*array)[10]     含义是array首先是个指针,它指向的是一个包含10个元素

的一维数组,即array指向一个数组,数组本身就是一个指针,那么array就是一个指向指针的指针,即array是一个第二维长度为10的二维数组。

 

5. 函数缺省参数

同一个函数只能定义一次,但是可以声明多次。函数的同一个参数只能声明一次缺省的参数。

void ff(int a, int b, int c = 0);     正确,声明一个函数,其参数c是有缺省参数的。

void ff(int a, int b, int c = 0){}     错误,定义这个函数,由于参数c已经指定了缺省参数,这里就不能再次指定了。

说明:我们一般把函数的缺省参数定义在函数的声明中,而在定义中不指定缺省

参数。

void ff(int a, int b, int c);     正确,再次声明这个函数,此时函数的c参数是带

有默认值的。

void ff(int a, int b, int c = 0);     错误,再次声明函数不能声明相同的缺省参数。

void ff(int a = 0, int b, int c);     错误,为a指定了缺省参数,那么a右边的参数必须全部都有缺省参数。

void ff(int a, int b = 0, int c);     正确,再次声明为参数b指定了缺省参数,这样在调用此函数时,bc都有缺省参数了。

注意:上面这中形式的声明并没有违反缺省参数的声明规则,由于c已经指定了

缺省参数,所以可以直接为b指定缺省参数,如果c没有指定缺省参数,那么此

声明就是错误的。

void ff(int a, int b = 0, int c = 0);     错误,不能重复指定参数的缺省值。

void ff(int a, int b = Default(), int c);     正确,缺省的参数可以是任何合法的表达式。

 

6. 省略号参数列表

C++中还保留了一个C方法的函数声明方式:函数的参数不定。

int printf(const char *, …);     这是C的格式化输出库函数,在调用时编译器只

检查第一个实参是否是const char * 类型,其他的

参数不检查,由编写值自己把握。

void fun(…);     函数调用时,编译器不检查函数的实参是否合法。

这种声明方法躲避了编译器的参数类型安全检查,不建议使用。

 

7. extern “C链接指示器

extern “C”有三种用法:

extern “C” void foo();     声明单条语句,函数fooC方式进行编译和链接

extern “C”{ void foo();  void fun(); }     声明一个语句段,语句段中的函数都是采用C方式进行编译和链接的。

extern “C”{ #include <math.h> }     声明一个头文件,文件中的函数都是采用C方式进行编译和链接的。

注意:链接指示器不允许出现在函数定义中。

8. 函数指针

给一个函数指针赋值,必须保证赋值运算符左边和右边的函数的返回值和参数完

全一致。

带省略号的函数指针和不带省略号的相同函数的函数指针不相同。

void printf(const char *, …);

void printff(const char *);

void (*pfun)(const char *) = printf;     错误,pfunprintf类型不一致

void (*pfun)(const char *) = printff;     正确,类型一致

C函数和C++函数指针也不一致。

extern “C” void printf(const char *);

void (*pfun)(const char *);     错误,C函数和C++函数类型不一致

extern “C” void (*pfun)(const char *);     正确,函数指针也是C类型函数

extern “C” typedef void (*Fun)(const char *);

Fun fun = printf;     正确,注意这里extern “C”typedef的位置

注意:下面两个定义含义不一致。

void (*pfun)(const char *);      定义了一个函数指针变量pfun,类型是

void (*)(const char *)

typedef void (*pfun)(const char *);     定义了一个函数指针类型pfun,可以用此类型来定义函数指针变量。如:

pfun p;     用函数指针类型pfun来定义一个变量p,此变量可以指向相同类型

的函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值