学过C语言的指针,我们知道,指针变量存的是其他变量的地址,其大小为4Byte(32位操作系统下;如果是64位操作系统,则为8Byte)。我们可以通过指针来间接修改变量的值。
在C++中,引用的应用场景与指针类似。引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
void test()
{
int a=0;
int& b=a;
b+=1;
cout<<a<<endl;
}
此时函数的调用结果为1,因为b是变量a的别名,两者指向同一块空间。
一、引用的有三个特性:
1、引用在定义时必须初始化(引用不能为空)。
2、一个变量可以有多个引用。
3、引用一旦引用一个实体,再不能引用其他实体。举个例子:看下面这个代码
void test()
{
int a=0;
int& b=a;
int z=10;
b=z;
cout<<a<<endl;
}
这段代码里b=z的作用是将z这一块空间里的值赋值给b指向的空间(即为a指向的空间),而不是将b作为z的别名。如果要将b作为z的别名,则需要重新定义b作为z的别名,但在一个程序中不能出现重定义。所以引用不能改变指向。
二、使用引用时要注意权限问题
权限只能缩小或平移
1、权限平移很容易理解,顾名思义引用类型必须和引用实体是同种类型的。
2、权限的缩小。下面的代码中,b是a的别名,但是有const修饰,所以不能通过b来对a进行修改,只能通过b来得到a的值。
void test()
{
int a=0;
const int& b=a;
}
3、权限不能放大。如下面这个例子就会报错。
void test()
{
const int a=0;
int& b=a;//这属于权限的放大,即a是常变量(不能改变),而b的实体类型定义的为int,即可以通过b来修改a的值,这样做是非法的,编译器会报错
}
4、其实C语言里也有相似的场景如下:指针p1里存放的是a的地址,且不能通过p1来修改a的值。
而p2指针里包含的是p1存放的地址,且int*前没有const修饰,则可以通过p2对*p1进行修改。
void test()
{
int a=0;
const int* p1=&a;
int* p2=p1;//这里编译器会报错
}
此外,这里还要注意的是,如果是const int* p1=&a;则不能通过*p1来修改a的值,但是可以改变p1所指向的空间。如果是int* const p1=&a;则可以通过*p1来修改a的值,但是不能改变p1所指向的空间。
三、引用时要注意“临时变量的问题”。
哪些场景下会产生临时变量呢?
1、类型转换(包括隐式类型转换和强制类型转换等)。
2、表达式。
临时变量具有常属性,因此要用const修饰。
void test()
{
double a=12.34;
const int& b=a;
int x=0,y=1;
const int& z=x+y;//如果写int& z=x+y会报错
}
四、引用和指针的不同点
1. 引用在定义时必须初始化,指针没有要求。
2. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型 实体。