您的位置:首页 > 编程语言 > C语言/C++

查漏补缺——函数(C++ Primer)

2016-07-06 10:52 465 查看
1、const形参和实参

(1)当用实参初始化形参时会忽略掉顶层const(作用于对象本身),换句话说,形参的顶层const被忽略掉了。当形参有顶层const时,传给它常量对象或非常量对象都是可以的:

void fcn(const int i){/*fcn能够读取i,但是不能向i写值*/}
//忽略掉形参的顶层const可能会产生意想不到的结果:
void fun(const int i);
void fun(int i);   //错误:重复定义了fun(int)


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

我们不能把const对象、字面值或者需要类型转换的对象传递给普通的引用形参。

2、数组形参

(1)数组有两个特殊的性质:不允许拷贝数组;使用数组时(通常)会将其转换成指针

因为不能拷贝数组,所以我们不能以值传递的方式使用数组参数。因为数组会被转换成指针,所以当我们为函数传递一个数组时,实际上传递的是指向数组首元素的指针。

尽管不能使用以值传递的方式传递数组,但是我们可以把形参写成类似数组的形式:

//尽管形式不同,但是这三个print函数是等价的,每个函数都有一个const int*的形参
void print(const int*);
void print(const int[]);
void print(const int[10]);  //数组的大小对函数的调用没有影响
//当编译器处理对print函数的调用时,只检查传入的参数是否是const int*类型


因为数组是以指针形式传递给函数的,所以函数并不知道数组的确切尺寸,调用者应该为此提供额外的信息。有三种常用的技术:数组本身包含一个结束标记(比如C风格的字符串以空字符结尾);传递指定数组尾元素和尾后元素的指针;专门定义一个表示数组大小的形参。

(2)只有当函数确实要改变元素值得时候,才把形参定义成指向非常量的指针,否则数组的形参应该设置成指向const的指针。

(3)将变量定义成数组的引用,注意维度是类型的一部分

void print(int (&arr)[10]) //&arr两端的括号必不可少
{
for(auto elem : arr)
cout<<elem<<endl;
}

//再一次强调
int *matrix[10];  //10个指针构成的数组
int (*matrix)[10];  //指向含有10个整数的数组的指针


3、引用返回左值

调用一个返回引用的函数得到左值,其他返回类型得到右值。可以像使用左值那样来使用返回引用的函数的调用,特别的,我们能为返回类型是非常量引用的函数的结果赋值。

4、主函数main的返回值

我们允许main函数没有return语句直接结束,这时候编译器将隐式插入一条返回0的return语句。

main函数的返回值可以看做是状态指示器,返回0表示执行成功,返回其他值表示执行失败。

cstdlib头文件中定义了两个预处理变量,我们可以用这两个变量分别表示成功或失败。使用return EXIT_FAILURE 或return EXIT_SUCCESS

5、函数的重载

我们知道,使得被修饰的变量本身无法改变的const是顶层const,其他的通过指针或引用等间接途径来限制目标内容不可变的const是底层const。

函数重载中的函数匹配,区分底层const,不区分顶层const

重载与作用域的关系:如果我们在内层作用域中声明名字,它将隐藏外层作用域中声明的同名实体,在不同作用域中无法重载函数名。

一旦在当前的作用域中找到了所需的名字,编译器就会忽略掉外层作用域中的同名实体,剩下的工作就是检查函数调用是否有效了。所以在不同的作用域中对函数的重载是失效的。

6、内联函数和constexpr函数

(1)内联函数可避免函数调用的开销:内联函数在它的每个调用点上“内联的”展开。而一般的函数调用包含一系列的工作:调用前要先保存寄存器,并在返回时恢复,可能需要拷贝实参,程序要转向一个新位置执行等。

在函数的返回类型前加上关键字inline即可声明为内联函数。内联机制用于优化规模较小、流程直接、频繁调用的函数。

(2)constexpr函数指能用于常量表达式的函数:定义constexpr函数要遵循几个约定:函数的返回类型及所有的形参的类型都是字面值类型,不过该函数不一定返回常量表达式;函数体中必须有且只有一条return语句

执行constexpr函数初始化任务时,编译器把对constexpr函数的调用替换成其结果值。为了能在编译过程随时展开,constexpr函数被隐式地指定为内联函数。

内联函数和constexpr函数通常定义在头文件中。和其他函数不一样,他们可以在程序中多次定义,但要保证多个定义必须完全一致。

7、调试帮助

(1)assert预处理宏

所谓预处理宏其实是一个预处理变量,它的行为有点类似于内联函数。

assert(expr);

首先对expr求值,表达式为假(0)时,assert输出信息并终止程序的执行,如果表达式为真(非0),assert什么也不做

(2)assert的行为依赖于一个名为NDEBUG的预处理变量的状态,如果定义了NDEBUG则assert什么也不做,默认状态下没有定义NDEBUG,assert将执行运行时检查。

#define NDEBUG

我们把assert和NDEBUG当成是一种调试程序的辅助手段,不能代替真正的运行时的逻辑检查,也不能代替程序本身应该包含的错误检查。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: