c++ primer 笔记第六章函数(二)
6.4 函数重载
同一作用域内名字相同形参列表不同的函数被称为重载函数。
main函数不能重载。
重载函数需要有形参数量或者形参类型不同,不允许除了返回值类型不同其它都相同的重载。
形参是否起名字不影响相同,顶层const不影响相同。底层const影响。
当传递实参为指向非常量的引用或指针,优先使用非常量版本的函数。
const_cast 对于使用带有底层const形参或返回值的函数很有用,注意是否安全。
为函数调用关联一个正确的函数叫做函数匹配,也叫重载确定。
函数匹配有三种情况:无匹配、有最佳匹配和二义性调用。
练习6.39 (a) 顶层const不影响形参的相同。 (b) 不应该只有返回值不同。 (c) T
6.4.1 重载与作用域
在不同的作用域无法重载函数,因为内层作用域的声明会隐藏外层声明。
编译器先对函数名进行查找,之后进行类型检查。
6.5 特殊用途语言特性
6.5.1 默认实参
在某些函数中每次调用有的形参都对应特定的实参,这些实参的值叫函数的默认实参。
默认实参作为形参初始值出现在形参列表中,有默认实参的形参后面的所有形参都要有默认实参。
默认实参应该放在函数声明里并放到头文件中。
默认实参负责填补函数调用缺少的尾部实参(右部)。
默认实参名字在函数声明的作用域内解析,但在函数调用时求值。
练习6.40 (b) 有默认实参的形参后面所有形参都要有默认实参。
练习6.41 (a) 非法,实参数量不对。 (b) 合法 (c) 合法但不符意图。
6.5.2 内联函数和constexpr函数
内联函数用于规模较小,流程直接,调用频繁的函数。很多不支持递归内敛。关键字inline。
constexpr函数是指能用于常量表达式的函数。函数返回值类型和所有形参类型都是字面值类型。
且有且只有一条return语句,可以有其它没有操作的语句。
constexpr函数不一定返回常量表达式。被隐式声明为内联函数。
内联函数和constexpr函数都放在头文件中。
练习6.43 (a) 头文件中,内联函数 (b) 头文件中 函数声明
练习6.46 不可以, 参数类型不是字面量类型。
6.5.3 调试帮助
assert预处理宏,assert(expr); 判断expr是否为真,为假则报错。在cassert头文件中。
NDEBUG预处理变量,如果定义该变量则assert什么都不做。
#ifndef NDEBUG {} #endif
C++ 四个调试函数的关键字 __FILE__ __LINE__ __TIME__ __DATE__ 字符串字面量和整型字面量。
练习6.47
void printV(vector<int> vec) {
#ifndef NDEBUG
cout << "size : " << vec.size() << endl;
#endif
if (vec.size() == 1)
cout << vec[0] << endl;
else {
cout << vec.back() << endl;
vec.pop_back();
printV(vec);
}
}
练习6.48 不合理, 应该判断s 与 sought是否相等。
6.6 函数匹配
先选候选函数:第一声明在调用点可见,第二函数名匹配。
然后从候选中选可行函数:第一形参与实参数量相同,第二实参类型与形参类型相同或可以转换。
第三步寻找最匹配的函数,即形参类型最匹配。
如果有多个形参且找不到最匹配的可行函数,那么就存在二义性调用。
练习6.49 候选函数和可行函数概念。
练习6.50 (a) 二义性调用 (b) f(int) (c) f(int, int) (d) f(d,d)
6.6.1 实参类型转换
1.精确匹配,包括数组转指针和顶层const。
2.const转换实现匹配。
3.类型提升。 4.算术转换。 5.类类型转换。
所有算术转换的级别都一样。
const引用和const指针对应的实参都是const类型,如果不是而需要const转换那么就不是精准匹配。
练习6.52 (a) 类型提升 (b) 算术转换
练习6.53 (c) 不区分顶层const
6.7 函数指针
函数指针指向函数,类型由返回类型和形参类型共同决定。
bool (*pf) (const string&, const string&);
pf = lengthCompare; pf = &lengthCompare;等价。
指向不同函数的指针不存在转换。指针可以赋值nullptr或者值为0的常量表达式。
重载函数的指针与重载函数精确匹配。
函数指针作为形参与声明类似。做形参时是否加*等价,做实参时用函数名自动转为指针。
使用类型别名和decltype简化使用,decltype返回函数类型,需要添加*。
返回指向函数的指针四种:1.类型别名 2.直接声明 int (*f1(int))(int*, int);
3.使用尾置类型 auto f1(int) -> int(*)(int*,int); 4.使用decltype,记得*。
练习6.54 int fn(int, int); vector<decltype(fn)*> int;
练习6.55
#include<iostream>
using namespace std;
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int mul(int a, int b) { return a*b; }
int divs(int a, int b) { return a / b; }
int main()
{
vector<decltype(add)*> v;
v.push_back(add);
v.push_back(sub);
v.push_back(mul);
v.push_back(divs);
for (auto x : v)
cout << x(30, 4) << endl;
return 0;
}
上一篇: JAVA 生成CSV文件
下一篇: centos7安装telnet