与C不同之处——引用

引用:

与C语言不同之处,c++这门语言多了一个用法——引用(&)
void swap(int l, int r)
{
int temp = l;
l = r;
r = temp;
}

在C语言中要想实现两个数的调用必须进行传址调用,但是还是上面的代码可以交换两个形参,但是并没有交换实参,只是进行了一份临时拷贝,并没有影响到实参,因此并没有发生交换。我们在c语言中通常进行传址调用,来交换两个数 。
void swap(int l, int r)
{
int temp = l;
l = r;
r = temp;
}
int main()
{
int a = 10;
int b = 20;
swap(&a, &b);
system("pause");
return 0;
}
这样就是通过传址实现了交换。我们还可以通过指针传递
void swap(int *l, int *r)
{
int temp = *l;
*l = *r;
*r = temp;
}
以将实参的地址传给形参(形参得到的依旧是一份拷贝,不过这次是地址的拷贝),然后函数内部就可以通过解引用(*指针名)的方式访问实参所在的空间,进而修改它的值。
但是到了c++,我们可以通过引用来交换
void swap(int &x int &y)
{
int temp = l;
l = r;
r = temp;
}

将参数定义为引用,这样实参传递过来时就相当于为l和r分别取一个别名,我们直接通过x和y这两个别名进行操作,省去了指针中解引用的操作。

int a=1;
int &b=a;
定义了a的一个引用b。通过对b的修改可以改变a。通过查看变量a和b的地址可以发现它俩拥有同一块空间,即并不为b分配新的内存空间(这里和指针不同)。我们为了简单理解可以把引用称之为取了一个别名。如这里b是a的一个别名,修改b就是修改a。
引用的特性:
1.引用在定义时必须初始化。
2.引用已经引用一个变量不能引用其他的变量。
int a=1;
int &b=a;
int c=2;
int  &b=c;//这样就不能通过。
3.引用必须同类型。
4.非常量引用的初始值必须为左值.
非常量引用,即没有加const修饰的引用,初始值必须为左值,NULL是左值吗?显然不是,所以直接将一个普通引用初始化为NULL(这里可以是任意常量)是不可行的(如果可行的话,通过这个引用岂不是可以修改常量了么?这怎么可以,所以不行)。

const修饰的引用:

1.const int &a=0;//const引用常量
2.
double d=0.0;
 int &a=d;
在VS2013下编译这条语句会得到这样的提示:

   无法用 "double" 类型的值初始化 "int &" 类型的引用(非常量限定).

但是加上const,如下:

double d=0.0;
 const int &a=d;
没有报错,我们查看反汇编得到以下代码:

     

double d = 0.0;
00815C98  movsd       xmm0,mmword ptr ds:[81DBB0h]  
00815CA0  movsd       mmword ptr [d],xmm0  
const int &a = d;
00815CA5  cvttsd2si   eax,mmword ptr [d]  
00815CAA  mov         dword ptr [ebp-28h],eax  
00815CAD  lea         ecx,[ebp-28h]  
00815CB0  mov         dword ptr [a],ecx  
运行到const int &a= d;语句时,(前两行生成一个d的临时值,后两行)并不是简简单单得到将a初始化为d的引用,而是产生了一个临时变量,而临时值是具有常属性,所以才可以赋给常引用 a。
要是这样:
double d = 0.0;
const double &a = d;
定义了一个常引用,使得 d 的值不能通过 a来修改(这种方法经常用到)通常会用在函数传参中,传给只需要访问d而不需要修改d的值的函数,保障了 d 的安全性。
查看反汇编:
double d = 0.0;
00C65C98  movsd       xmm0,mmword ptr ds:[0C6DBB0h]  
00C65CA0  movsd       mmword ptr [d],xmm0  
const double &a = d;
00C65CA5  lea         eax,[d]  
const double &a = d;
00C65CA8  mov         dword ptr [a],eax 

引用大小:

一个引用的大小与它所引用的对象的类型有关。

例如前一个例子中的引用:const double &a= 0; 那么sizeof(a)的大小将会是sizeof(double)的大小,在32位平台上,这个值是8。

引用作为返回值:

  1. int & fun()  
  2. {  
  3.     int a = 10;  
  4.     return a;  
  5. }  

比如我们再main函数中这样调用这个函数:int &b = fun();

有没有问题?仔细想想,可以发现,变量a的空间是在属于fun函数的栈桢上开辟的,变量a在fun函数返回后被销毁,此时它的值不在有效,也不能保证其值不变,返回这个变量的引用,相当于返回了栈空间的地址,那么b所引用的空间已被释放,它的值将会变得不可预料。当然指针的使用中也存在这样的错误例子(返回了栈空间地址)。

我们换个方式接受一下函数的返回值:int b = fun(); 这样依旧会存在一定的问题,函数的返回值是个引用(底层实现为指针),而函数返回值是通过寄存器实现的,则函数调用完成后,变量a的地址将被保存到寄存器中用以返回,然后函数栈桢销毁,再把这个地址的值赋给变量b。在此过程中也不能保证a所在空间的内容不发生改变,所以依旧有错。






























  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值