执行函数的第一步是(隐式地)定义并初始化它的形参。所以,函数最外层作用域中的局部变量也不能使用与函数形参一样的名字。
局部静态变量:在程序的执行路径第一次经过对象定义语句时初始化,并且直到程序终止才被销毁。在此期间即使对象所在的函数结束执行也不会对它产生影响。
Best Practice:熟悉C的程序员常常使用指针类型的形参访问函数外部的对象。在C++中,建议使用引用类型的形参代替指针。
使用引用避免拷贝:因为:拷贝大的类类型对象或者容器对象比较低效;有些类类型根本不支持拷贝操作;
当用实参初始化形参时会忽略掉顶层const。
我们可以使用非常量初始化一个底层const对象;但是,反过来不行。
尽量使用常量引用。
1 string::size_type find_char(string &s, char c, string::size_type &occurs); 2 find_char("hello world", 'o', ctr);//用字面值常量绑定到string引用,编译错误 3 4 bool is_sentence(const string &s) 5 { 6 string::size_type ctr = 0; 7 return find_char(s, '.', ctr) == s.size() - 1 && ctr == 1;//错误 8 }
(上述两种错误)
数组的两个特殊性质对我们定义和使用作用在数组上的函数有影响,这两种性质分别是:1)不允许拷贝数组;2)使用数组时会将其转换成指针。
- 管理指针的三种常用技术:
1. 使用标记指定数组长度,典型示例是C风格字符串
1 void print(const char *cp) 2 { 3 if (cp) 4 while (*cp) 5 std::cout << *cp++; 6 }
2.使用标准库规范:传递指向数组首元素和尾后元素的指针
1 void print(const int *beg, const int* end) 2 { 3 while (beg != end) 4 std::cout << *beg++ << std::endl; 5 }
3. 显示传递一个表示数组大小的形参:在C程序和过去C++程序中常用这种办法
1 void print(const int a[], size_t size) 2 { 3 for (size_t i = 0; i != size; ++i) 4 std::cout << a[i] << std::endl; 5 }
含有可变形参的函数:C++11风格:1)如果所有实参类型相同,可以传递一个名为initializer_list的标准库类型;2)如果实参类型不同,可以使用可变参数模板;C风格:3)varargs
与vetor不同的是,initializer_list对象中的元素永远是常数值,无法更改。
- return
返回一个值的方式和初始化一个变量或形参的方法完全一样:返回的值用于初始化调用点的一个临时量,该临时量就是函数调用的结果。
调用一个返回引用的函数得到左值;其他返回类型得到右值。
C++11可以列表初始化返回值。
- 返回数组指针
如果我们想定义一个返回数组指针的函数,则数组的维度必须跟在函数名字和形参列表之后。
1 int(*func(int i))[10]; 2 //func(int i)表示调用func函数需要int参数 3 //(*func(int i))意味着我们可以对函数调用的结果执行解引用 4 //(*func(int i))[10]表示解引用将得到一个大小是10的数组 5 //int(*func(int i))[10]表示数组中的元素是int类型
C++11新方法:尾置返回类型
auto func(int i) -> int (*) [10]
亦或者使用decltype,但是记住:decltype并不负责将数组类型转换成对应的指针,所以decltype结果是数组
1 int odd[] = { 1,3,5,7,9 }; 2 int even[] = { 0,2,4,6,8 }; 3 decltype(odd) *arrPtr(int i) 4 { 5 return (i % 2) ? &odd : &even; 6 }
- 函数重载与函数匹配
顶层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作用于函数时,返回的是函数类型而非指针类型。