引用
前言
本章我们将学习C++中的引用内容。此内容也是相当的重要,因为引用的话,它是对标我们此前在C语言学习的指针,我们都知道指针对于C语言的根基。
所以,引用对于整个C++的学习是至关重要的
引用的内涵
相信大家从小到大,身边的人或者自己或多或少也被别人取过“外号”吧?例如有个人叫做小红。那么比较调皮的同学可能就会给这位小红同学取外号,会叫他“猴子”、“西红柿”之类的外号。那我们知道,这个“猴子”、“西红柿”都是指的同一个人,也就是小红。
所以,像这给变量(也就是上面所说的小红)取别名(也就是外号)的行为,就叫做引用。
引用的语法规则以及注意事项
假设我们这里定义一个int类型的变量,我们要给它取别名,语法上怎么操作呢?
代码如下:
int main()
{
int a = 10;
int & b = a;//这里的b就是a的别名,a就是b,b就是a
}
所以引用的语法规则就是:被引用对象的类型 + & +引用的名字(也就是外号)我们再举一个例子:
int main()
{
double c = 3.14;
double & d = c;//说明了d是c的引用,d就是c,c就是d
}
此外,我们需要注意的是,一般我们只给变量作引用,数组函数之类的引用并没有多大的意义。
引用的特点
(1)我们可以对一个变量取多个引用,即:
int main()
{
int a = 10;
int & b = a;
int & c = b;//这里的b就相当于a了,给b取别名就相当于给a取别名
}
这里的b和c都相当于这里的变量a,也就是它们表现的都是同一块空间。我将作图表示:

可以看到,a、b、c都是指向同一块内存空间
那么,接上面的代码,我们再来看一组代码:
int main()
{
int a = 10;
int & b = a;
int & c = b;
int & d = a;
//自此,abcd都指向了10,我们来看看下面的代码
int x = 20;
c = x;
}
下面加的这两行代码是什么意思呢?谁发生了改变呢?提示一下,C++是从右向左赋值的。
3
2
1
答案揭晓,是将20赋值给了c,又因为c是a的别名,bd也是,所以abcd都由原先存放的10变成了20;也就是说

这就从侧面反映出了,假如bcd全都是a的别名,对a进行++,也就是对bcd也++,具有一致性。
引用的功能
(1)
以前我们想交换两个变量的值,通常是把两个两个的地址一一传过去,用指针变量接收,再通过中间变量进行一个交换。
那么我们现在学习了引用,也明白引用就是一个变量的别名,那么我们可以别名来接收需要交换的变量,因为那个别名也指向那个需要交换的变量
具体的操作,如下:
void Swap(int & x,int & y)//x是a的别名,y是b的别名
{
int tmp = x;
x = y;
y = tmp;
}
int main()
{
int a = 5;
int b = 10;
Swap(a,b);
return 0;
}
这样看,我们实现了在不使用指针的前提下,改变了两个变量的值。
(2)
我们在使用结构体的使用,假如里面的成员很大的话,我们又想对这个结构体变量初始化,那么再创建一个变量的话,就会占用内存很大的一块空间,运行效率也会下降,所以我们用引用来接收这个结构体变量。
代码如下:
struct A
{
int arr[100];
double d;
}
void structinit(struct A & aa)//aa是a的别名,用来代替a来对a进行初始化
{
int i = 0;
for(i = 0;i<100;i++)
{
aa.arr[i] = i;//对数组arr进行逐个的赋值
}
aa.d = 3.14;
}
int main()
{
struct A a;//创建结构体a变量
structinit(a);//把a传过去
return 0;
}
传值返回
我们的函数都很多的返回值类型,例如void,就是不返回任何值;int,就是返回整型值,传引用返回,就是返回某个变量的别名
在开始讲传引用返回时,我们来看看函数的普通返回类型有什么特点
我们先来看一段代码正不正确:
int func(int i)
{
return i;
}
int main()
{
int a = 5
int x = func(a)++;
return 0;
}
上面我对函数func的返回值进行了++,那么这样做是对的吗?在判断对错之前,有一个知识大家得了解
对于任何函数,只要这块函数中的程序运行结束了,那么这块函数空间就会还给操作系统了,所以上述的func函数是否实实在在的把“i”返回到主程序(main函数)中呢?显然答案是否定的,因为在返回i的过程中,中途会产生一个临时变量,才把这个临时变量返回到main函数中,而临时变量又具有常性,具有常性的意思就是无法被修改,就比如我们的10它也是常量,我们无法去修改10这个常量是一个道理。
所以我们这里的func(a)++是可以被执行的吗?那是不可以的,因为func(a)是一个临时变量,具有常性,无法被修改.
传引用返回
那么返回值是某个类型的返回值就是传引用返回,那么,我来为大家科普一下传引用返回的知识点
假如返回某个变量的别名,那个变量出了函数还在的话,那就是安全的;假如出了函数那个被返回的对象出了函数就销毁了,那么就是不安全的
第一种情况,代码如下:
int & func(int ret)
{
return ret;
}
int main()
{
int a = 10;
int x = func(a);
return 0;
}
上述代码是不安全的。用x来接收ret的别名,但是出了func函数后,func里面的东西就已经归还操作系统了,假设后面有人用了这一块已经被归还操作系统的func内存空间,就有可能改变了这个ret的值,那么返回的就不是原先的ret了,所以这种行为是不安全的
第二种情况,代码如下:
typedef int Sldatatype;
typedef struct Slist
{
Sldatatype *arr;
int top;
int capacity;
}Sl;
int & func(Sl & sl,int i)
{
return sl->arr[i];
}
int main()
{
Sl sl;
Slintt(&sl);//对sl初始化
Slpush(&sl,1);//对顺序表打入一个数据1
int i = 0;
int x = func(&sl,i);<------------
return 0;
}
箭头指向的代码行就是正确的,因为sl->arr[i]这块内容是通过动态内存扩展的空间,只要我们不主动释放,这块空间会一直存在,所以出了这个函数,sl->arr[i]的内存还是存在的,所以返回其别名是安全的。
引用与指针的不同
(1)引用必须初始化,指针初不初始化都可
因为引用一开始就得确认是谁的别名,不然取引用就没有意义了。指针不初始化就是空指针NULL
(2)引用无法改变指向,指针可以
我是你的别名就是你的别名,无法成为别人的别名。但是指针就可以改变指向的对象,我可以存放a的地址,那我也可以转而存放b的地址
(3)引用不开空间,指针开空间
(4)两者的sizeof函数不同
在64为位操作系统中,指针位8个字节的大小。而引用就是某个类型的大小,例如a是int型,b是a的别名,那么sizeof(b)= 4;


被折叠的 条评论
为什么被折叠?



