浅墨浓香

想要天亮进城,就得天黑赶路。

导航

第12课 经典问题解析一

Posted on 2016-04-10 21:24  浅墨浓香  阅读(533)  评论(2编辑  收藏  举报

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标识符都是只读变量