C++引用的基本
上节花了大量的时间讲指针。C/C++之指针(下)
本节我们介绍引用。
-
引用,是C++新引进来的一种概念,C中没有。
-
回顾变量名:
变量名实质是一段连续储存空间的别名,是一个标号。
程序中通过变量来申请并命名内存空间。
通过变量的名字可以直接使用存储空间。 -
概念:
引用可以看作一个已定义变量的别名。 -
语法:
使用取地址符&,
Type& name = var;
不能这样定义:int& name;
不做初始化。除非做函数的形参。 -
使用:
#include <stdio.h> using namespace std; int main(){ int a = 0; int& b = a; printf("a = %d, b = %d\n", a, b); printf("修改b\n"); b = 100; printf("a = %d, b = %d\n", a, b); printf("地址:&a = 0x%p, &b = 0x%p\n", &a, &b); return 0; }
输出结果:
a = 0, b = 0 修改b a = 100, b = 100 地址:&a = 0x0093FAA0, &b = 0x0093FAA0
结果很显然,两个改变一个,两个都会变。
-
前面在讲函数的时候,说过变量传递到函数中是简单的值传递,一般通过指针来进行操作,但是使用引用会很方便!而且比指针还不易出错。
例子:交换两数的函数。#include <stdio.h> using namespace std; //版本1普通的值传递 void swap1(int a, int b) { int tmp; tmp = a; a = b; b = tmp; } //版本2指针 void swap2(int* a, int* b) { int tmp; tmp = *a; *a = *b; *b = tmp; } //版本3引用 void swap3(int& a, int& b) { int tmp; tmp = a; a = b; b = tmp; } int main(){ int a = 30, b = 50; printf("未修改前:a = %d, b = %d\n", a, b); //版本1 swap1(a, b); printf("使用版本1:a = %d, b = %d\n", a, b); //版本2 swap2(&a, &b); printf("使用版本2:a = %d, b = %d\n", a, b); //版本3 swap3(a, b); printf("使用版本3:a = %d, b = %d\n", a, b); return 0; }
输出结果:
未修改前:a = 30, b = 50 使用版本1:a = 30, b = 50 使用版本2:a = 50, b = 30 使用版本3:a = 30, b = 50
结果:版本2和版本3都对两数进行了交换,优点是引用更加简洁。就相当于函数形参a, b成为了实参a, b的别名。
引用做函数的参数时不需要初始化! -
总结:引用作为其他变量的别名而存在,因此再一些场合可以代替指针。
引用相较于指针有更好的可读性和实用性。 -
思考:引用占用内存吗?一个变量可以有多个别名吗?
#include <stdio.h> using namespace std; int main(){ int x = 10; int y = 100, z = 1; printf("给x整三个别名前地址:x = %d, y = %d, z= %d\n", &x, &y, &z); return 0; }
输出结果:
给x整三个别名前地址:x = 7339464, y = 7339452, z= 7339440
观察:三个变量之间的内存大小为12个字节。
#include <stdio.h> using namespace std; int main(){ int x = 10; int& a = x, & b = x, & c = x; int y = 100, z = 1; printf("给x整三个别名后:x = %d, a = %d, b = %d, c = %d\n", x, a, b, c); printf("给x整三个别名后地址:x = %d, y = %d, z= %d\n", &x, &y, &z); return 0; }
输出结果:
给x整三个别名后:x = 10, a = 10, b = 10, c = 10 给x整三个别名后地址:x = 18349452, y = 18349404, z= 18349392
观察:此时x与y的地址相差48 = 12 * 4字节,而y与z相差12字节,所以引用也是占内存空间的。
-
总结:引用可以定义多个,而且它有自己的空间。别名一旦初始化后,无法再指向别的变量!(与常量指针很相似能改变值,但不能指向别的地址),实际上其实就是常量指针。
-
扩展:C++编译器在背后做的工作。
其实C++编译器偷偷的把引用换成了常量指针!#include <stdio.h> using namespace std; void swap(int& a, int& b) { int tmp = a; a = b; b = tmp; } void swap(int* const a, int* const b) { int tmp = *a; *a = *b; *b = tmp; } int main(){ int a = 10, b = 30; //调用引用 swap(a, b); //偷偷换成 swap(&a, &b); return 0; }
上面把调用的函数偷偷更换了。
-
本质:
Type& name;
等价Type* const name;
- C++编译器在编译过程中,使用常指针作为引用的内部实现,因此引用所占用的空间大小与指针相同!
- 它占空间。
- 只是为了方便开发,只有分析奇怪的语法时才会去分析编译器怎么做的。
下节我们介绍指针引用。