引用的概念与性质:
引用 其实很好理解 通俗的来讲就是给一个东西取一个 别名 就像是我们生活中的 “外号” 一样我们叫一个人的名字他会答应 叫他的外号也会答应
引用不是新定义一个变量,而是给已存在的变量取了一个别名,编译器不会为引用变量额外开辟空间,他和他引用的变量共用一块空间
所以呢 一个变量的别名和他的地址是一样的 一方改变另一方也就跟着变了 所以我们的swap函数也就可以这样写了
void swap(int* p, int* q)//C语言 { int tmp = *p; *p = *q; *q = tmp; } void swap(int& p, int& q)//C++ { int tmp = p; p = q; q = tmp; } int main() { int a = 10, b = 20; swap(&a, &b); cout << " a = " << a << " b = " << b << endl; int c = 10, d = 20; swap(c, d); cout << " c = " << c << " d = " << d << endl; }
这里两个 swap重名 是没有问题的 这个是 c++ 中的函数的重载 两个函数函数名相同 参数的数量,类型,类型的顺序不同 那么他们在一个作用域中是可以同时存在的
还有几个要注意的点:
- 我们的引用在定义的时候必须初始化 不能先定义 后面再初始化
- 一个变量可以有多个引用 就像我们的第一张图片 b c d都是a的引用
- 引用一旦引用一个实体,就不能够引用其他的实体了
- 不能给常量取别名 除非加const修饰
关于第三个点 大家来看这张图片看看是什么意思?
大家 觉得这里的 c=d 是什么意思呢 是变更 c 引用的量 还是给 c 赋值呢?
其实第三个特性已经很显然了 我们引用完一个实体就不能再取引用其他的实体了(好像物品们不能拿 甲同学 的外号 去叫 乙同学) 所以这里的答案就必然是赋值了
注意:C语言中的指针是可以改变所指向的对象 初始化后 还可以更改
当然我们的引用也是可以用到 const 的 大家看一下这下面的几种情况
const int a = 10; int& b = a; const int a = 10; const int& b = a; int a = 10; const int& b= a;
大家觉得这里面的代码 那些是不可行的呢? 其实很显然就是一个肯定是不行的 !!
因为 我们对一个变量取别名 别名相对于原引用变量的权限是只能 缩小 不能够 放大 的
像这里的const就是一个减少权限的操作 被const修饰下的变量就变成只读 不能修改了(如果是一个变量有多个指针或者是多个引用 其中一个被const修饰 也仅仅只能代表我们不能通过这个被修饰的指针或引用来改变这个变量 其他的指针或引用还是可以改变他的)
double a = 3.333; int b = a; double a = 3.333; int& b = a; double a = 3.333; const int& b = a;
大家看这几个代码有问题嘛?
第一个: 我们知道C语言里面中 如果两个类型不同的变量赋值是会发生 隐形转换 的 此时的a 其实并不是直接就把值给过去的 首先 a 会把它的浮点数部分丢掉后 把剩余的部分给到一个临时变量中 再从这个临时变量把值赋给b
第二个: 我们的引用的初始化的时候 如果遇到这种情况一样也是会产生一个 临时变量 而不能直接把 b 作为 a 的引用是因为 临时变量是具有常性的(被const修饰) 我们一个权限小的怎么能赋值给一个权限更大的变量呢?
注意:这是一个很重要的点 临时变量是具有 常性 的就相当于是这个临时变量是被 const 修饰过的
所以我们的第三个代码就是正确的 那有的人就会问了“为什么引用的部分初始化遇到有临时变量 要用const修饰 可是我们的 int b=a 不用这样修饰呢?”
首先对于这种赋值的操作只有使用 引用和指针 时 一个变量的改变才会影响到另一个变量 而对于这种平常的变量赋值是不需要的 在这里 我们的 变量的值赋值给了b 那么b的改变会影响我们的临时变量嘛 他们是拷贝的关系阿 是不会有影响的
此时我们再来看我们的第三个代码 那么此时我们的 b 就是 临时变量 的 别名 了!!!那么此时我们这个临时变量的生命周期就跟着 b 走了