c++primer阅读笔记之函数

函数

参数传递

  • 形参的初始化与变量的初始化一样,如果形参具有非引用类型,则复制实参的值;如果形参为引用类型,则它只是实参的别名(通过这句话我们可以发现,如果形参为非引用类型,那么我们是无法通过函数来改变实参的值的,对于指针也是一样,如果我们的参数为一个指针,那么我们只能通过函数来改变指针指向对象的值,但无法改变指针本身的值,因为此时的形参也只是实参指针的复制)
  • 如果函数的形参为一个指向const对象的指针,那么给该函数传递的实参不能是一个指向非const对象的指针。因为一个指向非const对象的指针是不能指向const对象的,而一个指向const对象的指针可以指向非const对象,但是不能改变该非const对象的值。此时,通过该函数,即无法改变对象的值,也无法改变指针本身的值
  • 因为进行参数的复制会带来很大的时间成本,因此如果我们不想复制参数,但又不想让函数改变实参的值,那么我们可以通过将形参定义为const引用来实现这个目的
  • 不能给一个非const引用形参的函数传递const型对象,因为如果这样可以得话,该函数就可以改变传进来的实参的值,这与const的特性相矛盾。因此,非const引用形参只能与同类型的非const对象相关联。因此,我们应该将不需要修改的相应的实参定义为const引用
  • 传递指向指针的引用(void ptrswap(int *&v1, int *&v2))
    • int *&v1可以理解为v1是一个引用,该引用与指向int型对象的指针相关联(注意这里是与指向int型对象的指针相关联,而不是与指针所指对象相关联,因此该函数可以实现指针的对换,即指针v1指向指针v2所指的对象,而v2则指向指针v1所指的对象)
  • 通常,函数不会用vector或其他标准库容器类型作为形参,因为调用含有普通的非引用容器形参的函数需要赋值该容器中的每一个元素。如果需要将容器作为形参,通常有两种方法:
    • 将容器类型的形参声明为引用类型,从而直接对该参数做操作,避免复制元素;
    • 通过传递指向容器中需要处理的元素的迭代器来传递容器
  • 处理数组的函数通常通过操纵指向数组中的元素的指针来处理数组,这样做的原因有两个:
    • 数组无法进行复制操作
    • 使用数组名时,数组名会自动转化为指向其第一个元素的指针
    • 当编译器检查数组形参关联的实参的时候,只会检查实参是否是指针,指针的类型和数组元素的类型是否匹配,而不会去检查数组的长度。但是如果数组形参声明为数组的引用(void printValues(int (&ary)[10])),编译器则不会将数组实参转化为指针,而是传递数组引用本身。这种情况下,编译器将会检查数组实参的大小与形参大小是否一致
    • 数组形参定义的三种等价方式
void printValues(int*){·····}
void printValues(int []){·····}
void printValues(int [10]){·····}   //这种格式很少使用
//这三种定义方式,形式不同,但是等价的,传入的实参均是指向数组元素类型的指针(通常直接是数组名,因为当实参为数组名时,会自动转换为指向第一个元素的指针)
  • 对于多维数组,除了第一维以外的所有维的长度都是元素类型的一部分,必须明确指定,其定义方式有两种
void printValues(int (matrix*)[10]);        //该指针指向包含10个int型元素的数组
void printValues(int matrix[][10]);

return语句

  • 千万不要返回局部对象的引用与指针,但是可以返回局部对象本身。这是因为对于引用与指针,一旦函数结束,局部对象将会被释放,此时返回的引用与指针将会指向不确定的内存,因为引用与指针是与对象相关联的。但是局部对象本身是没有关系的,因为返回局部对象本身,实际上返回的是局部对象的复制,这时候即使局部对象在函数结束后被释放,其复制品依然存在,所以没有关系。而局部对象的引用与指针则不同,因为其返回是引用与指针的复制,而不是对象本身的复制

静态局部对象

静态局部对象是指一个变量位于函数的作用域内,但生命周期却跨越这个函数的多次调用,即该对象一经创建,在程序结束前不会被撤销。我们用static来声明该对象

int count(){
    static int ctr = 0;
    return ++ctr;
}
int main(){
    for(int i = 0; i != 10; ++i)
        cout << count() << endl;
    return 0;
}
//该函数会输出1到10,共10个数,而不是10个0,这就是静态局部对象的好处,其会保留上次调用时的值

内联函数

对小操作定义函数的好处

  • 使用函数会更容易理解
  • 如果需要任何修改,修改函数要容器更多
  • 使用函数可以确保统一的行为,每个测试都可以保证以相同的方式实现
  • 函数可以重用,无需为其他应用重写代码

使用内联函数的原因

当我们调用一个函数的时候,往往需要首先保存寄存器,然后再复制实参,然后再转向一个新位置执行函数,最后恢复寄存器,这样我们会浪费很多的时间,时间成本要比直接执行函数中语句要慢很多,为了解决这个问题,提出了内联函数

什么是内联函数

如果我们将一个函数指定为内联函数,那么其会在程序中的每个调用点内联的展开。
我们通过在函数返回类型前加关键字inline就可以将该函数指定为内联函数

内联函数使用范围

通常,内联机制适用于优化小的,只有几行的而且经常被调用的函数。大多数编译器都不支持递归函数的
内联函数通常应该在头文件中定义,这样可以保证其在所有源文件中,定义都是相同的,并且可以保证该函数的定义在调用点对于编译器来说是可见的

重载函数

重载函数简述

重载函数是指在相同的作用域内,具有相同名字但形参不同的两个函数

  • 这里的形参不同有如下几种情况:

    • 参数个数相同但类型不同
    • 参数类型相同但个数不同
    • 参数类型与个数都不相同
  • 如果不在相同作用域内,那么局部作用域定义的函数将会屏蔽掉外层作用域定义的相同名字的函数,而不是重载

note

  • 函数不能仅仅基于返回值的不同而实现重载
  • main函数不能重载
  • 对于参数,非引用的const对象和非引用的非const对象被看做相同的参数,这是因为在传递实参的时候,对于非引用对象,无论是const还是非const,都是进行复制操作,并没有什么不同,因此会直接忽略const这个特性,故对于非引用对象,const与非const被视作相同的参数,不能实现那重载。
  • 对于引用型对象和指针型对象,是否为const则不同,这是因为对于引用型对象,传递进来的是其所关联的对象本体,故const还是非const所能执行的操作讲完全不同,同样,对于指向非const对象的指针和指向const对象指针也将完全不同,此时利用这两种参数的不同,可以实现重载
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值