1. 引用的意义
(1)引用作为变量别名而存在,因此在一些场合可以代替指针
(2)引用相对于指针来说,具有更好的可读性和实用性
2. 特殊的引用——const引用
(1)const Type& name = var; //让变量拥有只读属性
(2)当使用常量对const引用进行初始化时,C++编译器会为这个常量值分配空间,并将引用名作为这段空间的别名。但这样用常量对const引用初始化将生成的是一个只读变量。
【实例分析】引用的特殊意义
#include <stdio.h> void Example() { printf("Example: "); int a = 4; const int& b = a;//变量a的别名,const让变量b具有只读属性 int* p = (int*)&b; //&b就是变量a的地址 //b = 5;//非法,因为用const修饰的引用,其代表的变量是只读的 *p = 5; //合法,修改变量a的值 printf("a = %d ", a); //5; printf("b = %d ", b); //5 } void Demo() { printf("Demo: "); //const引用 const int& c = 1; //引用本应是变量的别名。一般,常量是不分配内存的。当编译器看 //该行时,会为常量1分配内存,并让b作为这段空间的别名。 int* p = (int*)&c; //c = 5;//非法,因为const修饰,c是只读的 *p = 5;//合法,通过指针访问内存 printf("c = %d ", c); //5 printf(" ", c); //5 //const修饰变量:注意与const引用的区别 const int a = 1; p = (int*)&a; //遇到&a才为常量分配内存 //a = 5;//非法,因为const修饰,a是只读的 *p = 5;//合法,通过指针访问内存 printf("a = %d ", a); //1,编译器看到a直接从符号表读其值(1) printf("*p = %d ",*p); //5 } int main() { Example(); printf(" "); Demo(); return 0; }
3. 引用的本质
(1)引用在C++中的内部实现是一个指针常量,因此引用所占用的空间大小与指针相同。
(2)从使用的角度,引用只是一个别名,C++为了实用性而隐藏了引用的存储空间这一细节。
①在编译过程中,编译器看到int& a的声明就会转换为int* const a;
②看到使用引用时,会转为*a,如此隐藏了使用指针的事实。
【编程实验】引用的思考
#include <stdio.h> struct TRef { char& r;//引用的本质是指针常量,因此会分配4字节的空间,相当于char* const r; }; int main() { char c = 'c'; char& rc = c; TRef ref = {c}; printf("sizeof(char&) = %d ",sizeof(char&));//1,char型变量别名,大小为1 printf("sizeof(rc) = %d ",sizeof(rc)); //1,变量c的别名,大小为1 printf("sizeof(TRef) = %d ",sizeof(TRef)); //结构体内有个引用,本质为指针,占4字节 printf("sizeof(ref.r)= %d ",sizeof(ref.r)); //1,char型变量的别名,大小为1 return 0; }
【编程实验】引用的存储空间
#include <stdio.h> struct TRef { char* before; //4字节 char& ref;//4字节,本质是指针常量,会分配4字节的空间,相当于char* const ref; char* after;//4字节 }; int main() { char a = 'a'; char& b = a; char c ='c'; TRef r = {&a, b, &c}; printf("sizeof(r) = %d ", sizeof(r)); //12 printf("sizeof(r.before) = %d ", sizeof(r.before)); //4 printf("sizeof(r.after) = %d ", sizeof(r.after)); //4 printf("&r.before = %p ", &r.before); printf("&r.after = %p ", &r.after); //after和before相差8个字节,中间隔了个b引用所占用的空间 return 0; }
4. 引用的意义
(1)功能性:引用在大多数情况下代替指针,可以满足需要使用指针的场合
(2)安全性:可以避开由于指针操作不当而带来的内存错误
(3)操作性:简单易用,又不失功能强大
【实例分析】函数返回引用
#include <stdio.h> int& demo() { int d = 0; printf("demo: d = %d ", d); //输出0 return d;//返回局部变量的引用,危险 } int& func() { static int s = 0; printf("func: s = %d ", s);//输出0 return s; //合法,返回的是静态局部变量(位于全局存储区中的) } int main() { int& rd = demo(); int& rs = func(); printf(" "); printf("main: rd = %d ", rd);//垃圾数值 printf("main: rs = %d ", rs);//0,返回全局存储区中的s printf(" "); return 0; }
5. 小结
(1)引用作为变量别名而存在,旨在代替指针
(2)const引用可以使得变量具有只读属性
(3)引用在编译器内部使用指针常量实现,其最终本质为指针
(4)引用可以尽可能的避开内存错误