引用的概念及用法
所谓的引用并非说从新定义的一个新的变量,而是给一个已经定义好了的变量起的一个别名。
下面看看引用究竟是如何使用的:函数
void test1()
{
int a = 1;
int& b = a; //引用变量b是a的别名学习
std::cout<<"a:address->"<<&a<<std::endl;
std::cout<<"A:address->"<<&b<<std::endl; //注意这里的&是取地址指针
a = 10;
b = 100;
std::cout<<"a = "<<a<<std::endl;
std::cout<<"b = "<<b<<std::endl;对象
int& c = b; //应用变量c是引用变量b的别名,别名的别名
c = 1000;
std::cout<<"a = "<<a<<std::endl;
std::cout<<"b = "<<b<<std::endl;
std::cout<<"c = "<<c<<std::endl;
}
运行结果以下: blog
由结果咱们能够看出引用变m量b与变量a的地址是同样的,该变b的值也会影响a。而且一个变量能够取多个别名,这里b是a的别名,c是b的别名,也就是a的别名了。就像咱们人同样,你有一个大名(身份证上的名字),可能还会有一个小名,也或许还会给本身起一个洋气的英文名,总之无论别人叫哪个名字,叫的都是你本人就对了。内存
总结:
一、一个变量能够有多个别名
二、引用必须初始化b
三、引用只能在初始化的时候引用一次,以后不能再引用其余的变量作用域
引用作参数
在以前的学习当中,咱们知道调用函数的传参有传值调用和传址调用。下面再来看一看这两种方式:test
一、传值调用变量
void swap(int a,in b)
{
int tmp = a;
a = b;
b = tmp;
}
//如今的咱们都知道了这样的函数是没法完成咱们但愿的交换功能的。
//究其缘由,就是由于这里使用的是传值方式,那么若是别人一旦想要
//调用我给我传两个参数,我就要生成两个局部的临时变量用来接收
//别人给我传的两个参数。可是当调用结束,函数栈帧释放,相应的
//用于接收参数的两个局部变量也会被一同释放掉,可是交换是发生在
//这两个局部变量之间的,如今他们已经被释放掉了,而且从头至尾
//都没有对调用方的两个想要交换的变量产生任何影响。所以这里的
//传值调用并完成不了交换的功能。
二、传址调用语法
void swap(int *a,int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
//所谓的传址调用就是传指针。
//如今咱们将两个形参改成指针,也就是说别人想要调用我完成交换功能时
//就将想要交换的两个变量的地址传给我就行了。函数调用期间对地址里面
//的内容进行交换,即使调用结束之后,函数栈帧被释放,可是是对两个地址
//的内容进行了交换,释放栈帧之后这两个地址并非函数栈帧里的,
//因此并不会一并被释放,而且完成了交换的功能。
三、传引用
void swap(int& a,int& b)
{
int tmp = a;
a = b;
b = tmp;
}
//咱们知道引用变量就是咱们给一个已经定义好的变量起的一个别名,
//因此说,若是咱们这里采用传引用的方式,那咱们这里的形参就是实参的别名
//在刚刚咱们也看了,变量和变量的别名,他们两个的地址是同一个,因此啊,
//这和传址调用有着殊途同归之妙。
引用作返回值
有时候咱们一个函数调用结束须要返回一些信息供调用方使用。好比说一个加法函数。
//方法一
int ADD(int a,int b)
{
int ret = a+b;
return ret;
}
//方法二
int& ADD(int a,int b)
{
int ret = a+b;
return ret;
}
//这里方法一是采用值的形式返回,而方法2是采用引用的形式返回。
//咱们能够看看汇编语言是如何这两种不一样返回方式的,以下图:
那么问题来了,咱们有该如何选择以那种方式返回呢???
一、若是返回的对象出了该函数做用域依旧存在,则使用引用返回,由于这样会更加高效
二、若是返回对象处了函数的做用域就不存在了,则使用值返回。
注意:不要返回一个临时变量的引用,由于临时变量在函数调用结束之后会随着栈帧的释放而被释放,而传引用返回的方式返回的是变量的地址,而事实是该变量已经被释放。
引用和指针的区别
在这以前咱们一直在说,引用是一个变量的别名,因此可能就会想到说这个引用变量时不会占据任何的空间的。可是!请注意!这种想法是不对的。引用变量也是会占据必定的内存空间的,也须要在栈上额外占用存储空间。
由于引用的底层实现实际上是指针。从语法上来看只是一个别名,但在底层上依旧是开辟了一块空间。
int main()
{
int a = 0;
int& b = a;
return 0;
}
看一下这段代码的汇编:是如何处理变量a,和引用变量b
从汇编咱们能够看出对引用变量初始化为a的别名,就是将a的地址给了引用变量b。想想这种方式是否是很熟悉?对了,正如你所想到的咱们常常写的一个代码:
int a = 0;
int *p = &a;
//取a的地址赋给指针变量p
这样看来其实引用的底层也就是一个指针,只不过明面上向咱们所展现的是一个变量的别名,但咱们应该注意引用变量是一个已经定义过的变量的别名,他是别名,他也占空间,由于他的底层实现是指针。
下面就看一看引用和指针的区别:
一、引用只能在定义时初始化一次,以后不能改变指向其余的变量,但指针能够。 二、引用必须指向有效的变量,但指针能够为空。 三、sizeof引用获得的是所指向的变量的大小,但sizeof指针是对象的地址的大小。 四、引用的自增(+ +)自减(- -)是对值的+1或-1,而指针++或–是+或-其所指向的类型大小。