《C++ Primer》读书笔记第六章-3-特殊特性 And 函数匹配 And 函数指针

笔记会持续更新,有错误的地方欢迎指正,谢谢!

特殊特性

这次介绍三种函数相关的语言特性,都挺有用的。

默认实参

//窗口函数的声明如下,带默认实参
string screen(int height = 24, int w = 80);

我们可以为一个或多个形参定义默认值。注意,一旦某个形参被赋予了默认值,它后面的所有形参都必须有默认值。

int f(int a = 24, int b); //这样的声明错误
int f(int a, int b = 24); //这样的声明正确
默认实参

如果我们想使用默认实参,只要在调用函数的时候省略该实参就可以了。
例如调用上面的screen函数:

string window;
window = screen(); //等价于screen(24, 80)

当然,我们也可以不使用默认实参来调用,只要指定实参的值就行:

window = screen(55); //等价于screen(55, 80)
window = screen(5535); //等价于screen(55, 35)

当然,你不能跳过一个默认实参去调用?
window = screen( , 60); //错误
所以,当设计含有默认实参的函数时,要合理设置形参的顺序,让经常使用默认值的形参在后面。

默认实参声明

可以多次声明同一个函数,但是,在给定的作用域中一个形参只能被赋予一次默认实参:

string screen(int height, int w = 24);
string screen(int height = 24, int w = 24);//错误:重复默认实参w,同一个值也不行。
string screen(int height = 48, int w); //正确。

总结:在给定的作用域中一个形参只能被赋予一次默认值,但可多次声明函数给不同形参赋予默认值。

内联函数和constexpr函数

调用函数虽然很方便但它也有缺点:调用函数比直接在主函数里面写逻辑要慢,因为调用前要保存寄存器,在返回时恢复;可能需要拷贝实参;控制权转换。

所以救世主出现内联函数可以避免函数调用的开销。感觉在打广告
1. 内联函数:直接把逻辑代码贴上去。一般只有当函数规模小、流程直接、无递归时,内联函数的请求才会被编译器接受。
其实,要实现内联函数,就是在函数的最前面加个关键字inline:
inline const string &shortStr(const string &s1, const string &s2)

2. constexpr函数:能用于常量表达式的函数,但返回值可以是非常量;返回和形参类型都是字面值类型,函数体中有且只有一条return语句;被隐式指定为内联函数。

3. 内联定义:和其他函数不同,内联和constexpr函数可以多次定义,因为要贴代码的话肯定要定义的,声明是不够的,但每次必须完全一致,通常定义在头文件中。

调试帮助

程序可以包含一些代码,只是用于调试的,发布的时候要屏蔽,这里介绍两个:assert和NDEBUG。

1. assert预处理宏
assert(expr);
首先对expr求值,如果为假(0),assert再输出信息并终止程序的执行;如果为真,assert什么也不做。
我觉得很好用,它可以帮你检查你想要检查的任何表达式的真假用起来很放心。

2. NDEBUG预处理变量
可定义预处理变量NDEBUG禁用assert的效果。

函数匹配

1. 函数匹配:先找到同名候选函数,再找到参数数量相等且类型相同或可强制转换的可行函数,再寻找其中最佳匹配的函数。
2. 最佳匹配:每个实参的匹配都不劣于其他可行函数,且至少有一个优于其他;若找不到最佳匹配则报二义性错误。
例子:

void f(int, double);
void f(double, int);
int main()
{
    f(1,1); //调用有二义性
    return 0;
}

实参类型转换

说白了就是实参这么传过去会不会有问题,跟变量赋值差不多的。
例子:

void f(int &); 
void f(const int &);
int a = 1;
const int b = 0;
f(a); //调用f(int &)
f(b); //调用f(const int &)
//其实f(a)也可以调用const,但是人家有完全匹配咯~

函数指针

声明指向一个函数的指针,只需要用指针替换函数名。
假设:函数的类型是bool (const string &, const string &)。要想声明一个指向该函数的指针:bool (*pf)(const string &, const string &)。括号不能少!!!

使用函数指针

把函数名作为值使用时,该函数自动转换为指针。(和数组名一样)
假设:pf是指向名为lengthCompare的函数。

bool b1 = (*pf)("hello", "Jay"); //对
bool b2 = pf("hello", "Jay"); //对
bool b3 = lengthCompare("hello", "Jay"); //传统写法,对

重载函数 的指针

重载函数 的 指针:指针类型必须与重载函数中的某一个 精确匹配。
补充:函数的类型由它的返回类型形参类型共同决定。

函数指针作为形参

void f(bool (*pf)(int));//形参是一个函数指针,这个指针指向的函数类型是 形参为int,返回类型是bool。

函数指针作为返回值

和数组类似,我们不能返回函数,但是可以返回函数指针。

using F = int(int*, int); //F是 函数类型
using PF = int(*)(int*, int); //PF是 函数指针类型
//为了方便,我直接使用了类型别名
//根据返回类型来判断几个表达式:
PF f1(int); //对,因为PF是 函数指针类型
F f2(int); //错,因为F是 函数类型233333
F *f3(int); //加*才对嘛
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值