一、引用定义
引用:给已经存在的变量取一个别名,并不是定义一个新变量。编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
ra就是a的引用,无论值还是地址都相同,使用同一块内存空间。
1. #include<iostream> 2. using namespace std; 3. 4. void f() 5. { 6. int a = 10; 7. int& ra = a; 8. 9. cout << "a = " << a << endl; 10. cout << "ra = " << ra << endl; 11. 12. printf("&a : %p\n", &a); 13. printf("&ra : %p\n", &ra); 14. } 15. 16. int main() 17. { 18. f(); 19. return 0; 20. }
注意:引用类型必须和引用实体是类型相同
二、引用特性
1.引用在定义时必须初始化,不能为NULL
1. #include<iostream> 2. using namespace std; 3. 4. void f() 5. { 6. int a = 10; 7. int& ra;//编译会报错,需要指定ra是谁的引用 8. } 9. 10. int main() 11. { 12. f(); 13. 14. return 0; 15. }
2.一个变量可以有多个引用,即可以有多个别名
1. #include<iostream> 2. using namespace std; 3. 4. void f() 5. { 6. int a = 10; 7. int& ra = a; 8. int& rb = a; 9. int& rc = ra; 10. 11. cout << "ra = " << ra << endl; 12. cout << "rb = " << rb << endl; 13. cout << "rc = " << rb << endl; 14. } 15. 16. int main() 17. { 18. f(); 19. 20. return 0; 21. }
这块空间既叫做a,又叫做ra、rb、rc
(3)引用一旦引用一个实体,就不能再引用其它实体
三、常引用
1.常引用声明
常引用声明方式:const 类型& 引用变量名 = 目标变量名
1. #include <iostream> 2. using namespace std; 3. 4. int main() 5. { 6. const int a = 10; 7. const int& ra = a;//正确常引用 8. 9. int& ra1 = a;//错误常引用 10. 11. return 0; 12. }
int& ra1 = a是错误引用,是因为变量a使用了const关键字,表明a的值不能被修改。但ra1作为a的引用,并没有使用const关键字,说明ra1的值可以被修改,这会导致权限被放大,编译器不允许:
虽然权限放大不被允许,但是权限缩小是允许的:目标变量没有const关键字修饰,常引用使用const关键字修饰,如下所示:
1. #include <iostream> 2. using namespace std; 3. 4. int main() 5. { 6. int b = 20; 7. const int& rb = b; 8. 9. return 0; 10. }
2.带有隐式类型转换的常引用
隐式类型转换:编译器自动将一种类型转换成另一种类型,是编译器的一种自主行为
在隐式类型转换过程中,会产生一个临时变量,类型为目标变量类型。
1. int c = 10; 2. double d = 1.11; 3. 4. d = c;//隐式类型转换,将int类型赋值为double类型
带有隐式类型转换的常引用如下所示:
1. int c = 10; 2. const double& rc = c;//带有隐式类型转换的常引用,将int类型赋值为double类型
(1)const修饰带有隐式类型转换引用的必要性
这是因为在隐式类型转换过程中,发生了类型赋值,这时候不是把c给rc,而是产生了一个临时变量,临时变量是double类型的。因此rc引用的并不是c,是这个过程中产生的临时变量,而临时变量具有常性,不可修改,因此rc要加上const关键字进行修饰。
(2)const修饰带有隐式类型转换引用的原因
如果rc不加const关键字进行修饰,rc引用临时变量,临时变量不可修改,但是rc又可读可写,那么rc即引用的权限就被放大了,这是不允许的。
监视可以看到程序执行完毕时,c的值并没有发生变化,d≠c,rc≠c,d和rc改变的是临时变量的值。