引言
《引用》属于C++的关键知识点,在各个项目中的应用非常广泛,掌握引用的相关知识点和使用方法,能够编写出更加简洁、安全和高效的代码,本篇文章整理总结了引用中的关键知识点。也许之前已经接触过了引用,但是没有详细的项目深入使用的话对引用的理解可能还会存在误区,在开始学习前,先思考一下图片中的几个问题,这几个问题也是在笔试或面试中常见的考点,文章将从这几个问题展开讲述。
概念梳理
本文主要介绍的是C++中的引用和指针,所以首先简单介绍C++中引用和指针的相关概念,对相关知识进行回顾。
引用
C++中的引用(Reference)是一种复合类型,它提供了对另一个变量的直接访问方式,就像它是那个变量的别名一样。引用在底层实现上通常是通过指针来完成的,但在语法和用法上,它们比指针更加直观和安全。
指针
C++中的指针(Pointer)是一种变量类型,它存储的是另一个变量的内存地址,而不是数据本身。通过指针,我们可以直接访问和操作存储在内存中的数据,而不需要通过变量名。
引用和指针的区别
通过上述概念可以直接理解,引用它是一个 变量的别名
,而指针是 存储变量地址的对象
。为了能够更直观的了解指针和引用的区别,可以通过观察引用和指针在使用时底层汇编语言的区别,观察下图可以加深了解。
a = 30; 在汇编中首先通过 mov eax,dword ptr [a] 获取 a(实际上是 x 的地址)到 eax,然后通过 mov dword ptr [eax],1Eh 将值 30(十六进制为 1Eh)存储到 eax 指向的地址(即 x 的地址)中。这里体现了引用的直接性,操作 a 就像直接操作 x 一样。
*p = 40; 在汇编中首先通过 mov eax,dword ptr [p] 获取 p(y 的地址的地址)到 eax,然后通过 mov dword ptr [eax],28h 将值 40(十六进制为 28h)存储到 eax 指向的地址(即 p 指向的地址,也就是 y 的地址)中。这里需要先通过 p 获取 y 的地址,然后才能操作 y 的值,体现了指针的间接性。
引用和指针在底层汇编语言中的语法都是一致的,所以说引用是更加安全的指针。它们之间的区别主要是下面两条。
①初始化要求
引用
必须在声明时被初始化,且一旦与某个变量绑定后,就不能再改变为引用另一个变量。也就是说引用变量的关联对象一旦确认以后就不能发生改变,不能与其他的对象进行关联。指针
在声明时可以不初始化(虽然这通常不是个好习惯),并且可以在任何时候重新指向其它地址。
②安全性问题
引用
在语法上更接近于直接使用变量,因此可以减少一些由于指针错误(如解引用空指针、野指针等)导致的错误。指针
提供了更大的灵活性,但也带来了更高的出错风险。需要更加小心地管理内存和指针的生命周期。
所以也可以说引用时一种更安全的指针,因为引用对象永远能够引用到对应内存,指针可能是一个空指针
总结
引用和指针的区别在于:从定义中来看,①引用是一种复合类型,而指针是一个变量类型;②引用提供了对另一个变量的直接访问方式,指针存储的是另一个变量的内存地址。
引用使用时注意的点
①必须完成初始化
②对于左值引用来说,初始化的对象能够取到地址(为左值变量)
函数中的使用
例如我们在书写swap函数的时候想要实现对数值的交换,可以有多种写法
void swap1(int a, int b)
{
int temp = a;
a = b;
b = a;
}
对于swap1,函数试图通过值传递来交换两个整数的值。然而,由于参数是通过值传递的,函数内对a和b的任何修改都不会影响传递给函数的原始变量。因此,这个函数实际上不会改变任何外部变量的值。
底层原理:
在调用swap1时,传递给函数的实际上是原始变量a和b的副本。函数内部对这两个副本的操作不会反映到原始变量上。
void swap2(int* a, int* b) // 接收变量的地址
{
int temp = *a;
*a = *b;
*b = temp;
}
对于swap2,这个函数通过指针传递来交换两个整数的值。参数a、b是变量的地址,是指向整数的指针,函数内部对指针解引用后的值进行的修改会直接影响原始变量。
底层原理:
在调用swap2时,传递给函数的是指向原始变量a和b的指针。函数内部通过解引用这些指针来访问和修改原始变量的值。
void swap3(int& a, int& b)
{
int temp = a;
a = b;
b = temp;
}
swap3函数使用了引用传递的方式来接收参数。这意味着,当我们将两个变量的名字(例如x和y)传递给swap3时,我们实际上是在告诉这个函数:“嘿,swap3,你直接操作这两个变量本身,而不仅仅是它们的副本。”这是通过int&(即整型引用的声明)来实现的。
左值引用和右值引用的区别
在C++11以后加入了右值引用这一概念,在认识右值引用前,先了解一下C++中左值和右值的概念。
- 左值是可以出现在赋值语句左边的表达式。它们表示持久的对象,具有稳定的内存地址。左值可以是变量、函数返回值(如果返回的是引用或指针)、解引用的指针等。左值可以被多次赋值,即可以在其生命周期内被修改。
- 右值通常表示临时的、非持久的数据,它们通常没有稳定的内存地址(虽然这并非绝对,比如某些实现可能会为右值提供存储位置以优化性能)。右值包括字面常量、表达式计算结果(除非该表达式的结果是引用类型)、函数调用(除非返回类型是引用或指针)等。
了解了左值和右值能够更好理解左值引用和右值引用的区别。
左值引用是我们在C++中经常遇到的引用类型。它是对左值的一个别名,通过引用可以直接访问和修改左值。左值引用用&符号表示,但注意这里的&是引用声明的一部分,不是取地址运算符。
int a = 10;
int &b = a;
右值引用是C++11引入的新特性,用于引用右值。通过右值引用,我们可以访问和修改那些即将被销毁的临时对象,从而可以实现资源的转移(如移动语义)而非拷贝,从而提高程序的性能。右值引用用&&符号表示。
int &&c = 20;
在这里c作为右值引用变量,
但是它本身是一个左值 ,只能使用左值对他进行引用
例如
c = 30; √ 对于右值引用变量能够对他重新赋其他右值对象。
int &&d = c; × 语法错误,c实际上是一个左值对象无法将右值引用绑定到左值
int &e = c; √ 使用左值引用绑定左值是正确的。
总结
引用和指针都是C++中非常重要的知识点,是笔试面试中常出现的考点,掌握这部分内容能够大大提高代码效率。
文章通过讲解C++代码的底层汇编语言来了解其中的特性,有些人获取不知道汇编语言该如何开启,可以参考http://t.csdnimg.cn/AP5bn这篇文章中的方式。希望能够帮到各位!