C++入门——引用和内联函数

大家好!这篇我们说一下C++里的引用,内容很干,希望能够一起进步。
在这里插入图片描述

1. 引用

1.1 引用概念

引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
写法如下:
类型& 引用变量名(对象名) = 引用实体;

void Test()
{
 int a = 10;
 int& b = a;//<====定义引用类型
}

注意:引用类型必须和引用实体是同种类型的。

1.2 引用特性

1.引用在定义时必须初始化
在这里插入图片描述
这样写就是不允许的。
2. 一个变量可以有多个引用
在这里插入图片描述
你会发现它们几个地址都是一样的。
3. 引用一旦引用一个实体,再不能引用其他实体
这个是什么意思?举个例子:
在这里插入图片描述
在这里,你会发现这里的a和b都被改成了20,但是a和b的地址和e不一样。
说明:e只是把值赋给了a,b,不是把b当作e的别名。

1.3 常引用

我们知道const可以修饰变量,但这里const也可以修饰引用。
取别名原则:对原引用变量,权限只能缩小,不能放大
什么意思呢?我来举个例子:
在这里插入图片描述
从这里,我们可以看见x给const修饰了,那么x只能读不能写。但这时,我们给x起别名时,没加const就是说它的权限变大了,可以读和写了。这是不允许的。
我们必须这样做:
在这里插入图片描述
那么缩小,肯定我们也能理解了。
在这里插入图片描述
此时,d的权限是缩小的,所以它只能读,不能写。
那么我们进行下一个问题:能不能给常量起别名。
在这里插入图片描述
从上面我们可以看到这样是不行的,我们必须加const修饰。
在这里插入图片描述
我们下面的情况:
在这里插入图片描述
我们知道:引用类型必须和引用实体是同种类型的,但我们加一个const就可以了
在这里插入图片描述
这是为什么呢?我们知道,如果一个浮点型的变量赋值给整型:
在这里插入图片描述
那么此时d会创建一个临时变量,d会把自己的整数部分放到这个临时变量里,然后赋给f。
在这里插入图片描述
那么上面的问题中,f其实真正引用的是d的临时变量,而临时变量具有常性。
如果没加const,那么权限就会放大,所以加上const就OK了。

1.4 引用的使用场景

1. 做参数
在这里插入图片描述
这样,我们就不需要使用指针,可以直接传过来,x和y就是c和d。
那么引用做参数有什么好处呢?
1.输出型参数(就是可以用来做输出的)
2.减少拷贝,提高效率。

2. 做返回值
在这里插入图片描述
我们先看这个代码,它是普通的传值返回。
在这里插入图片描述
其实传值返回时也会产生一个临时变量,如果n小就会存n的值,如果大就不存。然后,把临时变量拷贝到ret。
那么为什么会产生临时变量呢?
我们平时是不会加static的,因为static可能会造成一些进程问题。我们平时都是这样写:
在这里插入图片描述
这样,如果我们没有临时变量,那么当Count函数结束时,n也会销毁,还给操作系统,n就无法给到ret。
但是,我们引用又有什么用呢?
在这里插入图片描述
如果,我们改成引用做返回值的话,是什么一个情况呢?
在这里插入图片描述
在传值返回:会有一个拷贝,创建临时空间。而在传引用返回:就没有这个拷贝,函数返回的直接就是返回变量的别名。
然后,这个别名再赋值给ret。
我们可以来验证一下:
在这里插入图片描述
这里,ret和n的地址一样,也就是意味着ret其实就是n的别名。
但是这里的代码,存在一些问题。就是当n销毁时,还给操作系统了,我们还有一个n的别名ret可以非法访问。
所以我们应该这样写:
在这里插入图片描述
这样当n不会被销毁时,我们就可以使用引用返回,这样就不会造成非法访问了。
所以要注意:如果函数返回时,出了函数作用域,如果返回对象还未还给系统,则可以使用引用返回,如果已经还给系统了,则必须使用传值返回。

1.5 值、引用效率比较

以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。

1.6 引用和指针的区别

在这里插入图片描述
为什么说它们的底层实现是一样的呢?我们可以看一下它们的反汇编:
在这里插入图片描述
我们可以看到,它们的汇编代码是一样的。

引用和指针的不同点:

  1. 引用在定义时必须初始化,指针没有要求
  2. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体
  3. 没有NULL引用,但有NULL指针
  4. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)
  5. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
  6. 有多级指针,但是没有多级引用
  7. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
  8. 引用比指针使用起来相对更安全

2. 内联函数

2.1 概念

inline修饰的函数叫做内联函数编译时C++编译器会在调用内联函数的地方展开,:没有函数压栈的开销,内联函数提升程序运行的效率。

为什么C++会增加内联函数呢?
因为在C语言里,如果我们频繁调用短小函数,就会频繁的开辟函数栈帧,效率就会低。所以C语言会使用宏来解决这个问题,但是宏的出错率高,所以C++就会出现内联函数。

那内联函数是这么用的呢?很简单:
在这里插入图片描述
如果在上述函数前增加inline关键字将其改成内联函数,在编译期间编译器会用函数体替换函数的调用。

2.2 特性

1. inline是一种以空间换时间的做法,省去调用函数额开销。所以代码很长或者有循环/递归的函数不适宜使用作为内联函数。
2. inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有循环/递归等等,编译器优化时会忽略掉内联。
3. inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。

第三个特性,我们来说一下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
当我们编译运行时,就会发生错误。
在这里插入图片描述
因为在编译时,.h会展开,inline会展开不会产生函数的地址,符号表里就没有函数的地址,当我们调用函数时,就会找不到函数。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学代码的咸鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值