今天,继续和大家分享关于引用的相关,以及更多关于C++入门的知识,包括内联函数,关键子auto,范围for和空指针。
以上就是我们本篇文章要了解的知识大纲,好了,我们现在继上篇文章继续了解引用的相关知识。
引用
上篇文章我们提到了
引用的三个重要特性:
第一点是:引用在定义的时候必须进行初始化,如下图所示
第二点是:一个变量可以有多个引用。什么意思呢?我们以下图变量x为例,变量x既可以叫a,也可叫b。a和b都是对x的引用
第三点:引用一旦引用了一个实体,就不能再引用其他的实体了。通俗来说,就是我给李华取了个绰号叫小华,就不能叫别人小华了。不然,很容易搞混,不清楚谁是谁。让我们来看看具体的代码:
以上是引用的三个重要特性,接下来,我们看看下面这张图:
从图中我们不能难发现,变量y的定义是错误的,而变量x的定义是正确的。这是为什么呢?这是因为数字10是常量,具有常性,不能更改。而我们现在给10取别名为y,y可以修改,如果y修改成功了,也就是10修改成功了,这不是扯蛋吗?所以,对于常量的引用我们需要加上const进行修饰,而对常量的引用,我们称之为常引用。
引用的使用场景
引用的使用场景,主要有两个。
第一个是做参数。引用做参数,我们可以直接对外部变量进行操作。其实,引用的引入是为了简化指针的一些繁琐操作,以前我们c语言在函数中想要对外部成员进行操作,又是取地址,又是一级指针,二级指针的,甚是麻烦,还容易出错。这就有了引用,甭管你是几级指针,引用都能解决。
引用作为参数有一个优势:提高效率(一些自定义类型会比较大,使用引用,就不需要对某个数据再进行拷贝,可以直接对相关数据进行访问,这样一来减小了空间时间上的开销,大大提高了效率)
第二个是做返回值。
引用作为返回值的优势,其实,也是提高效率。对于一些大的类型,能使用引用就使用引用(主要还是依照情况而定)。
引用基本任何场景下,都能使用,但是要注意,引用的对象实体出了作用域(也可以理解为函数结束),还存不存在。如果不存在,还使用引用就会造成非法访问。
以上是引用的两个主要的使用场景,在这些场景的使用过程中,会涉及到一些权限问题。
引用的权限问题
我们先看一下,下图的引用是否存在问题
从图中我们可以看出,编译器已经标识红线报错了。这是为什么呢?这是由于变量a被const修饰,表示不能被更改。而变量b是对a的引用,并没有用const修饰,权限被放大,出现了冲突。我本身不可以修改,而到了你哪里就可以修改了,这不是扯蛋吗?
那下面这种方式,是否存在问题呢?
从图中我们不难发现编译器并没有报错提示,说明这种方式是合法的。有些不细心的同学就会问,为啥,前面那种情况会出现问题,而上面这种却合法呢?当我们细心查看时,不难发现,变量d并不是对变量c的引用,只是对变量c的拷贝,这并不涉及权限的放大的问题。
我们来看看下面这种情况是否存在问题:
从上图我们不难发现,编译器并没有进行报错。这是为什么呢?这是因为在引用的过程,权限的缩小和平移是被认可的。
那下面这种情况是否符合权限的平移或缩小呢?很明显,答案是否定的。
一些细心的同学就会发现,它们的类型不同,那报错的原因是不是如此呢?
从上图看,编译器很明显没有报错,我们刚刚的猜想是错的。那原因出在哪呢?这是由于变量e赋值给变量b时,发生了类型转换,由double变成int,而类型的转换会生成临时变量,而临时变量具有常性,也就是不能被修改,所以,需要加上const修饰。
这种情况,还会在做返回值的时候出现。
从上图中,我们不难发现,编译器报错了,这种情况与前面的一种情况类似,值返回,产生了临时变量,而临时变量具有常性,属于权限被放大了,我们可以用下面两种方式解决。
通过对引用权限问题的学习,我们发现引用的出现并不都是好的,也存在弊端。接下来,我们探讨一下,指针和引用的区别
指针和引用的区别
首先,第一点:从语法层面看,指针需要开辟空间,而引用不需要。从底层看,引用是通过指着实现的,两者都需要开辟空间。
第二点:引用必须初始化,指针可以不初始化
第三点:引用一旦引用实体就不可以改变了,而指针可以改变所指向的对象
第四点:有多级指针,但没有多级引用
第五点:没有NULL引用,但是又NULL指针
第六点:引用相对于指针更安全
第七点:访问实体的方式不同,指针需要显示访问,引用由编译器自动处理
第八点:sizeof计算引用,所引用实体类型的大小,而计算指针,始终是计算指针类型的大小
第九点:引用自身加1,是引用实体加1。而指针自身加1,是指针向后偏移一个类型的大小
关于引用,我们就先学到这。
接下来,我们来了解一下,内联函数
内联函数
宏相信大家都不陌生,就是将某些值替换成相应的英文名称,写到程序中。内联函数,也是类似的。当我们写的程序中,有使用内联函数,编译器就会将使用内联函数的地方,用该内联函数的实现方式替换掉,通俗说,将函数展开。而我们把这种会在编译过程中展开的函数,称之为内联函数。
对于内联函数,我们该如何定义呢?方法很简单,在函数定义前加上inline。这里需要注意:内联函数的声明和定义不能分开
我们加上inline后,函数是不是一定是内联函数呢?当然不是,编译器并不相信我们。只有那些短小的函数,才适合做内联函数。但并不是每个人都会遵守规定,有些人会在一个非常长的函数前加上inline,如果让这个函数成为内联函数,会造成程序执行效率极大降低。所以,一个函数,是否成为内联函数,编译器说的算。
关于内联我们就先学到这,接下来,我们来了解C++的一个关键字auto
关键字auto
auto这个关键子对于初学者用处不大,但到了后面,十分好用。好用在呢?它可以自动推导等号右边的类型。这样干着讲体会不到它的妙处,让我们来看看代码:
从上图中,我们可以感受到auto的优势和便捷,今后,还会有更长的类型,这时候使用auto就非常的方便。对于auto的使用,我们需要注意它不能作为函数参数、返回值,以及数组的直接类型。
对于auto,它常会于范围for结合使用
范围for
范围for是一个语法它,可以帮助我们更加便捷的访问一段范围的数据。让我们来看看它的效果。
从图中看,相信屏幕前的你,已经感受到它的魅力了吧。范围for会自动判断结束,自动迭代,依次取出数组的值赋给变量e。
对于范围for的使用条件,就是有具体的范围。对于数组而言就是第一个元素到最后一个元素。对于类就是begin()到end()。
对于范围for的知识,我们就先了解到这。
接下来,我们了解一下nullptr.
nullptr
对于空指针NULL,相信大家都不陌生。在传统的C头文件(stddef.h)的空指针NULL,它的本质是一个宏,内容是0。
这就导致了一些问题的出现,比如下面这种:
从图中,我们可以看到,我们本意是通过NULL来调用fun(int*),但由于NULL被定义为0,这就导致了程序与现实相悖。为了解决这一问题,C++就引用了nullptr来作为空指针。
好了,到这里,本次的分享就到此结束了,不知道我有没有说明白,给予你一点点收获。如果你有所收获,别忘了给我点个赞,这是对我最好的回馈,当然你也可以在评论发表一下你的收获和心得,亦或者指出我的不足之处。如果喜欢我的分享,别忘了给我点关注噢。