引用
1.基本概念
- 引用不是定义一个变量,而是给已经存在的变量取了一个别名(就像我的名字叫J,别人给我起了一个外号“二狗”,当别人叫“J”或者“二狗”我都知道是在叫我),编译器不会为引用变量开辟内存空间他和他引用的变量共用一块内存空间。
类型& 引用变量名(对象名) = 引用实体;
定义引用
int main()
{
int a = 10;
int& ra = a;//定义引用,
//char& ra = a;//错误,引用类型必须和引用实体类型相同
cout << a << endl;
cout << ra << endl;
}
2.引用特性
- 引用在定义时必须初始化
- 一个变量可以有多个引用,但是引用一旦引用一个实体,就不能再引用其他实体。
int main()
{
int a = 10;
int& ra;
cout << a << endl;
cout << ra << endl;
}
- 为什么引用在定义时就要初始化呢?因为如果定义时不初始化,它就再没机会去引用其他实体。
int main()
{
int a = 10;
int b = 20;
int& ra = a;
int& rra = a;//多个引用可以引用同一个实体
int& ra = b;//但是引用一旦引用一个实体,就不能再引用其他实体
cout << a << endl;
cout << ra << endl;
}
3.常引用
int main()
{
const int a = 10;
//int& ra = a; //编译时会出错,因为a是常量
const int& ra = a;//如果a是常量,要引用的话,必须加const
const int& rb = 10;//10也是常量,所以也要加cosnt
}
4.使用场景
- 作为函数形参
void Swap(int& ra, int& rb)
{
int tmp = 0;
tmp = ra;
ra = rb;
rb = tmp;
}
int main()
{
int a = 10;
int b = 20;
Swap(a, b);
cout << a << " " << b << endl;
}
打印结果如图,这里可以将a ,b交换。
- 作为函数返回值
int& add(int& ra)
{
ra += 10;
return ra;
}
int main()
{
int a = 10;
add(a);
cout << a << endl;
return 0;
}
- 注:不能返回栈空间上的引用。
5.如何引用一个数组
int main()
{
int i = 0;
int a[10] = { 0 };
int b = 20;
int (&ra)[10] = a;//引用一个数组
for (; i < 10; i++)
cout << ra[i] << " ";
cout << endl;
return 0;
}
6.引用和指针的区别
int main()
{
int a = 10;
int& ra = a;
int *pa = &a;
}
将上面的代码调试,鼠标右击转到汇编,得到如下图的汇编代码
不难发现,引用和指针的汇编代码完全相同,在这里引用实质上就是 int* const pa。
总结:
相同点:
- 引用和指针底层的实现方式相同,都是按照指针的方式来实现的
不同点:
- 引用在定义时必须初始化,指针则不用;
- 引用只能引用初始化引用的对象,而指针可以在任何时候指向任何一个同类型对象;
- 没有NULL引用,但有NULL指针。
- 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终都是4字节(32位);
- 引用自加改变变量内容,指针自加改变指针指向;
- 有多级指针,但是没有多级引用;
- 指针需要手动寻址,引用通过编译器寻址;
- 引用比指针使用起来相对安全;