Chapter6:函数

执行函数的第一步是(隐式地)定义并初始化它的形参。所以,函数最外层作用域中的局部变量也不能使用与函数形参一样的名字

局部静态变量:在程序的执行路径第一次经过对象定义语句时初始化,并且直到程序终止才被销毁。在此期间即使对象所在的函数结束执行也不会对它产生影响。

Best Practice:熟悉C的程序员常常使用指针类型的形参访问函数外部的对象。在C++中,建议使用引用类型的形参代替指针

使用引用避免拷贝:因为:拷贝大的类类型对象或者容器对象比较低效;有些类类型根本不支持拷贝操作;

当用实参初始化形参时会忽略掉顶层const。

我们可以使用非常量初始化一个底层const对象;但是,反过来不行。

尽量使用常量引用

 string::size_type find_char(string &s, char c, string::size_type &occurs);
find_char("hello world", 'o', ctr);//用字面值常量绑定到string引用,编译错误 bool is_sentence(const string &s)
{
string::size_type ctr = ;
return find_char(s, '.', ctr) == s.size() - && ctr == ;//错误
}
(上述两种错误)

数组的两个特殊性质对我们定义和使用作用在数组上的函数有影响,这两种性质分别是:1)不允许拷贝数组;2)使用数组时会将其转换成指针。

  • 管理指针的三种常用技术

1. 使用标记指定数组长度,典型示例是C风格字符串

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

2.使用标准库规范:传递指向数组首元素和尾后元素的指针

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

3. 显示传递一个表示数组大小的形参:在C程序和过去C++程序中常用这种办法

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

含有可变形参的函数:C++11风格:1)如果所有实参类型相同,可以传递一个名为initializer_list的标准库类型;2)如果实参类型不同,可以使用可变参数模板;C风格:3)varargs

与vetor不同的是,initializer_list对象中的元素永远是常数值,无法更改。

  • return

返回一个值的方式和初始化一个变量或形参的方法完全一样:返回的值用于初始化调用点的一个临时量,该临时量就是函数调用的结果。

调用一个返回引用的函数得到左值;其他返回类型得到右值。

C++11可以列表初始化返回值。

  • 返回数组指针

如果我们想定义一个返回数组指针的函数,则数组的维度必须跟在函数名字和形参列表之后。

 int(*func(int i))[];
//func(int i)表示调用func函数需要int参数
//(*func(int i))意味着我们可以对函数调用的结果执行解引用
//(*func(int i))[10]表示解引用将得到一个大小是10的数组
//int(*func(int i))[10]表示数组中的元素是int类型

C++11新方法:尾置返回类型

auto func(int i) -> int (*) []

亦或者使用decltype,但是记住:decltype并不负责将数组类型转换成对应的指针,所以decltype结果是数组

 int odd[] = { ,,,, };
int even[] = { ,,,, };
decltype(odd) *arrPtr(int i)
{
return (i % ) ? &odd : &even;
}
  • 函数重载与函数匹配

顶层const不影响传入函数的对象。

函数匹配有三种结果:1)找到最佳匹配;2)无匹配;3)二义性匹配;

如果我们在内层作用域中声明名字,它将隐藏外层作用域中的同名实体。在不同作用域中无法重载函数名。在C++中名字查找发生在类型检查之前。

函数匹配的步骤

(1)寻找候选函数:1)与被调用函数同名;2)声明在调用点可见;

(2)寻找可行函数:1)形参与实参数量相等;2)对应类型相同或者是能转换成形参类型

(3)寻找最佳匹配:实参类型与形参类型越接近,匹配得越好

匹配等级具体排序如下

1.精确匹配:分情况:1)实参类型与形参类型相同;2)实参从数组类型或函数类型转换成指针类型;3)实参添加/删除顶层const。

2.通过const转换实现的匹配;

3.通过类型提升实现的匹配(有int型形参,有short形参,则char直接提升为int)

4.通过算术类型转换实现的匹配,所有转换等级都一样;

5.通过类类型转换实现的匹配。

在给定作用域中一个形参只能被赋予一个默认实参,换句话说,函数的后续声明只能为之前那些没有默认值的形参添加默认实参。

默认实参的解析求值发生在函数调用时。

constexpr函数不一定是常量表达式。

把内联函数和constexpr函数放到头文件中,编译时使用。

调试帮助:

assert的行为依赖于NDEBUG的状态,如果NDEBUG定义了,那么assert什么也不做。

函数指针:decltype作用于函数时,返回的是函数类型而非指针类型。

上一篇:每周一荐:学习ACE一定要看的书


下一篇:C#_项目做成安装包