1、引用的概念
引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空
间,它和它引用的变量共用同一块内存空间。
类型& 引用变量名(对象名) = 引用实体;
void Test()
{
int a = 10;
int& ra = a;//ra是a的别名,可以理解为外号/昵称,即一块值为10的空间,名称为a或ra
printf("%p\n", &a);
printf("%p\n", &ra);
}
语法上面,ra是a的别名,不开空间;
底层实现,引用是通过指针实现的。
2、引用的特性
2.1 引用在定义时必须初始化
引用在定义时必须初始化,否则会报错。
2.2 一个变量可以有多个引用
void Test()
{
int a = 10;
int& ra = a;
int& rra = a; //一个变量可以有多个引用
cout << &a << endl<< &ra<< endl << &rra;
}
2.3 引用一旦引用一个实体,再不能引用其他实体
void Test()
{
int a = 10;
int b = 100;
int& ra = a;
ra = b;//此时是赋值,将b的值给a
cout << a<<" "<<b << " " <<ra << endl;
cout << &a << " " << &b << " " <<&ra;
}
a=ra=b=100,a和ra的地址是一样的,b又是不同的地址
3、使用场景
3.1 做参数
void Swap(int& left, int& right)//可以直接相互交换left和right的值
{
int temp = left;
left = right;
right = temp;
}
引用做参数的作用是:1、介绍拷贝,提高效率(特别是在排序中,会大量使用Swap函数,引用做参可以提高效率);2、输出型参数,函数中修改形参,实参也修改了
3.2 做返回值
3.2.1 传值返回
int count()
{
static int n = 0;
n++;
return n;
}
int main()
{
int ret = count();
ret = count();
cout << ret << endl;//此时ret的输出结果为2
return 0;
}
n的值是先copy给临时变量,然后临时变量再copy给ret,这就是传值返回。
3.2.1 引用返回
int& Count()
{
static int n = 0;//这里n的类型必须是static int。如果n是int型,出了函数作用域,返回变量不存在了,不能用引用返回,因为返回结果是未定义的。出了函数作用域,返回变量存在,才能用引用返回
n++;
// ...
return n;
}
int main()
{
int ret = Count();
cout << ret << endl;
return 0;
}
传引用返回的作用是:1、减少拷贝,提高效率;2、修改返回值
4、 常引用
void func(const int& x)//一般用引用做参数都是用const引用
{
}
int main()
{
int a = 10;
int& ra = a;//属于权限平移
const int b = 1;
a = b;//指针和引用复制时,权限可以缩小,但是不能放大.注意a修改,不会影响到b,所以可以a=b
//int& rb = b;//权限放大,不行。b只读,rb是可读可写,所以不行
const int& rb = b;//属于权限平移
const int& rra = a;//rra引用a,权限缩小,可以
//int& c = 10;//该语句编译时错误,因为常数10具有常性,在引用时必须加const
double d = 12.34;
//int& rd = d;//该语句编译时错误,因为类型不同
const int& rd = d;
func(a);
func(b);
func(rra);
return 0;
}
以上是常引用的几种用法,特别要注意权限的放大和缩小。权限的缩小和平移是可以的,放大是不行的。
double d=12.34;
int i=(int)d;//强转
int i=d;//d先拷贝给临时变量,临时变量再拷贝给i,临时变量具有常性