C++ primer 读书笔记(9)

函数的声明

在函数声明里值得注意的一点是默认形参(default parameter)的声明。默认形参即在调用函数时可以省略实参的形参,所以我觉得也可以翻译成缺省形参。在声明函数时就显式地给这些参数赋值了,如果没有传入实参,则直接使用默认值,如果传入实参,就会覆盖原来的默认值。有人可能会担心,既然可以省略实参,那么在调用函数时怎么知道到底省略了哪些参数呢?为了消除歧义,首先,在声明函数时,其参数列表中一旦出现了默认参数,其后的参数必须都是默认参数;第二,在调用函数时,只能按顺序为默认参数传入实参,不能跳跃,见下例:

void fun(int height=80, int width=40, char background='*'){...}
fun();    //由于所有形参都是默认参数,可以无实参调用函数
fun(50);  //只提供一个实参一定是传给第一个默认形参的,即给height赋值50
fun('*'); //虽然形式上是正确的,但是实际上‘*’传给了height,因为不可能跳过height和width直接给background赋值

由以上两条,我们可以得到实践上的第三点:在提供函数列表时,把最有可能使用默认值的参数放在最后面,把最不可能使用默认值的参数放在最前面,这样才能有效减少默认参数的输入,设想如果反过来,就算我们要使用默认值,由于要对后面的参数赋值,必须对前面的默认参数再输入一遍默认值。

对象的存在时间

我们知道变量的使用范围这个概念,对象的存在时间也同样是有限制的。我们把在函数内定义的一般对象称为自动对象(automatic objects),它们会随着函数的运行结束而被清除,此后无法再使用这个对象(在语句块内定义的对象会在语句块结束后被清除)。当然,如果我们想让对象在函数结束后依然存在,可以定义静态局部对象(static local objects)。举个例子如下:

size_t count_calls()
{
    static size_t ctr=0;
    return ++ctr;
}

int main()
{
    for (size_t i=0;i<10;++i)
        cout<<count_calls()<<endl;
    return 0;
}

注意:在调用count_calls之前就已经建立了对象ctr并且初始化为0,此后每次调用函数,ctr的值自增,在函数结束时其不会被清除。程序输出1到10.


inline函数

简单的讲,inline函数就是直接将函数内容替换掉函数调用的位置然后直接执行的函数。因为对于一般的函数,我们使用时是要通过调用的,函数调用有一定的时间代价,比如中断处理和返回,保存寄存器的内容,将实参赋值给形参,程序控制分支跳转等等。有什么办法可以避免这些耗时呢,简单的做法就是在编译的时候就将函数的所有操作插入到所有调用该函数的位置,执行的时候就可以顺流直下,不需要中断,这就是inline函数,我们在声明函数时在其返回类型前面加上inline关键字就可以了。例如:

inline const string &shorterString(string &s1, string &s2)
{
    return s1<s2?s1:s2;
}

这样所有调用shorterString的地方在编译时都会被直接变成执行s1<s2?s1:s2,大大减少耗时。也许有人奇怪,既然这样,为什么还要定义这个函数而不是直接写语句呢?

原因有四:

1. 如果有很多地方需要这个计算,每个地方都要写一遍这些语句,如果需要修改,则要一个一个的改,但如果定义了函数,就只用改一次;

2. 从函数名可以判断所执行操作的目的,比直接写语句具有更高的可读性;

3. 写成函数有利于复用,在其他程序里也可以直接拿来用;

4. 可以保证每次调用函数执行的是一致的操作,如果一个一个写语句,可能会出现错误导致不同地方执行的操作不同

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值