在理解引用概念前,先回顾一下变量名。
变量名实质就是一段连续存储空间的别名(内部有自己的编号),是一个标号(门牌号),程序需要通过变量来申请并命名内存空间(编译器建立与内存地址的联系)?
那么问题来了,一段连续的内存空间只能取一个别名吗?显然不是,引用的概念诞生了。
在C++中新增了引用的概念,引用是一个已定义变量的别名。其语法是 Type& name = var; 例如:
int a = 10; //c编译器分配4个字节内存。a内存空间的别名
int&b = a; //b就是a的别名。。。
思考1:如何使用引用?引用的价值如何体现?
引用做函数参数,回想经典的交换两个变量的值,形参和指针做函数参数传递的效果。地址传递和值传递的区别,引用不就是地址的别名吗?这样就可以有效的解决这个问题了。
引用做函数参数时需要区别普通引用。普通引用声明时必须要初始化。而引用做函数参数不需要初始化。从例子中来理解为什么可以这样。
struct Teacher
{ charname[64];
intage ;
};
void printfT(Teacher *pT)
{ cout<
}
void printfT2(Teacher &pT)
{ //cout<
pT.age= 33;
}
void printfT3(Teacher pT)
{
cout<
pT.age= 45; //只会修改pT变量 ,不会修改t1变量
}
void main()
{ Teachert1;
t1.age= 35;
printfT(&t1);
printfT2(t1);//pT是t1的别名
printf("t1.age:%d\n", t1.age); //33
printfT3(t1);// pT是形参 ,t1 copy一份数据给pT //---> pT = t1
printf("t1.age:%d\n", t1.age); //35
cout<<"hello..."<
system("pause");
return;
}ok,我们知道了如何使用引用了,那么引用的意义和价值又是什么呢?我们继续讨论。
引用的意义:既然引用作为其他变量的别名而存在,那么在很多场合是不是可以代替指针呢,因而也具有更好的可读性和实用性。这就是引用存在的意义。
引用看起来非常简单易理解,不就是给一个变量重新取一个名字吗?需要使用变量的时候就派它代替源变量去处理,并具有一样的处理权利。引用给程序员带来了非常便捷的处理方式,那么C++编译器又是如何提供这种处理机制呢?下面我们进入到引用的本质探讨。
2. 引用的本质思考
int a = 10;
int &b =a; //b是a的别名,请问c++编译器后面做了什么工作?
printf("sizeof(b)%d\n", sizeof(b)); 普通引用有自己的空间吗?
(深入理解的关键)引用在C++中内部实现是一个常指针。Type& name <--> Type*const name
这么做事为了实用性做出的细节隐藏
void func(int &a) void func( int *const a)
{ a=5; { *a =5;
} }
请试着思考:对比间接赋值成立的三个条件:1. 定义两个变量(一个实参,一个形参)
2. 建立关联,实参去地址传递给形参
3. *p形参去间接修改实参的值。
在引用的实现上,将后两步合为一步完成,不需要通过去地址去修改实参的值。传递过来的就是实参地址,直接通过别名修改即可。
似乎现在已经对引用有了更深刻的理解,接下来我们进入到一个新的认识高度:常引用
常引用就是const修饰的引用
请思考 cost int &a = b PK const int &a = 10;
这就是常引用初始化的两种形式:左边用变量,右边用常量。
左边是常见的方式应该很好理解,右边请思考去掉关键字const会怎样?即 int &a=10; 显然是不行的,引用是对变量去别名,字面常量10 是没有内存空间的,不能做引用。但是加长const之后,编译器就会为常量分配内存空间,并将引用名作为该内存空间的别名。最后总结常引用使得变量具有只读属性(可以通过指针修改)引用无法修改(别名)。
至此,引用的基本类型已经分析结束。