1. 关于const的疑问
(1)const常量的判别准则
①只有用字面量初始化的const常量才会进入符号表,如const int i = 1;
②使用其它变量初始化的const常量仍然是只读变量。如const int a = b;//a为只读变量
③被volatile修饰的const常量不会进入符号表,如volatile const int i = 1;//这时会为i分配内存,且i每次都是从内存中取值。加const只是说明i不能作为左值。
▲在编译期间不能直接确定初始值的const标识符,都被作为只读变量处理。
(2)const引用的类型与初始化变量的类型
①当用变量来初始化与const引用时,如果两者类型相同,则初始化变量成为只读变量。
②当用变量来初始化与const引用时,如果两者类型不同,则将生成一个新的变量,即引用的是另一个新变量,而不是原来的用来初始化引用的那个变量。
【编程实验】const典型问题分析
#include <stdio.h> int main() { //实验1:初始化变量的类型与引用类型相同时 const int x = 1; const int& rx = x;//x与rx的类型相同,所以rx为只读变量,不能作为左值 //但本质上还是变量,引用x的内存值(而不是符号表中的值) int& nrx = const_cast<int&>(rx);//转为普通引用 nrx = 5; //nrx与rx都引用了x的内存值 printf("x = %d\n", x); //1,从符号表中读取 printf("rx = %d\n", rx); //5,从内存中读取 printf("nrx = %d\n", nrx); //5,从内存中读取 printf("&x = %d\n", &x); printf("&rx = %d\n",&rx); printf("&nrx = %d\n",&nrx); //x、rx、nrx地址相同 //实验2:初始化变量的类型与引用类型不同时 char c = 'c'; char& rc =c; const int& trc = c;//c与trc类型不一致,则会生成一个新的变量,然后trc引用这个新的变量 rc = 'a'; printf("c = %c\n", c); //c printf("rc = %c\n",rc); //c printf("trc = %c\n",trc);//a printf("&c = %p\n", &c); printf("&rc = %p\n",&rc); //rc与c的地址相同 printf("&trc = %p\n",&trc);//trc是一个新的地址 //实验3:volatlie volatile const int y = 2; //volatile修饰,分为y分配内存 int* p = const_cast<int*>(&y);//因y被const修饰,不能作为左值 *p = 6; //因y不能作为左值,用来代替y = 6;这样的写法 printf("y = %d\n", y);//6,volatile指示y得从内存中读取 printf("p = %p\n", p);//y的地址 const int z = y; //用变量初始化const常量,z不会进入符号表,z分配内存 p = const_cast<int*>(&z); *p = 7; printf("z = %d\n", z);//7,因z没进入符号表 printf("p = %p\n", p);//z的地址 return 0; }
2. 关于引用的疑问
(1)指针与引用的不同
|
指针 |
引用 |
初始化 |
值是一个内存地址,不需要初始化 |
必须在定义时初始化,之后无法代表其它变量 |
访问内存 |
通过指针可以访问对应内存地址中的值 |
对引用的操作(赋值,取地址等)都会传递到其代表的变量上。 |
const修饰 |
被const修饰成常量或只读变量。 如const int* p;//p |
const引用,表示其代表的变量具有只读属性。如,const int& a等价于const int* const a; |
(2)从使用C++语言的角度来看,引用与指针没有任何关系。引用是变量的新名字,操作引用就是操作对应的变量。当进行C++编程时,直接站在使用的角度看待引用,与指针毫无关系,引用就是变量的别名。
(3)从C++编译器的角度来看,在编译器内部,使用指针常量来实现“引用”。因此,“引用”在定义时必须初始化。当对C++代码进行调试分析时,一些特殊情况,可以考虑站在C++编译器的角度看待引用。
【编程实验】引用典型问题分析
#include <stdio.h> int a = 1; struct SV { int& x; int& y; int& z; }; int main() { int b = 2; int* pc = new int(3); //将sv各成员初始化为变量a,b,*pc等内存的引用 SV sv = {a, b, *pc}; printf("&sv.x = %p\n", &sv.x);//变量a的地址,全局区 printf("&sv.y = %p\n", &sv.y); //变量b的地址,栈 printf("&sv.z = %p\n",&sv.z); //new出来的地址,堆 //在C++中没有“引用数组”的概念,请看如下分析 //对于数组而言,其内存是连续分布的。当进行&array[1] - &array[0] //表示前后两个元素的地址相差的值,应等于sizeof(元素的类型)。 //但如果允许定义“引用数组”的话,如下面语句,&array[1]表示第1个元素 //的地址,即元素b的地址(&b),而&array[0]表示&a,显然这两个地址是不连续的。 //所以int& array[]={a, b, *pc};//这样的定义是错误的,C++里不支持“引用数组” return 0; }
3. 小结
(1)指针是一个变量,而引用是一个变量的新名字
(2)const引用能够生成新的只读变量
(3)在编译器内部使用指针常量实现“引用”
(4)编译时不能直接确定初始值的const标识符都是只读变量