C++深度解析 经典问题解析---const和引用,只读变量和常量,引用和指针(11)【详细】

C++深度解析 经典问题解析 const和引用,只读变量和常量(11)【详细】

 

 

 

对于const的疑问

const常量判别准则

  • 只有用字面量初始化的const常量才会进入符号表,是真正意义上的常量
  • 使用其他变量初始化的const常量仍然是只读变量
  • volatile修饰(易变的,可能发生变化的)的const常量不会进入符号表,volatile const同时修饰的标识符,得到的是只读变量。
  • const引用的类型初始化变量的类型相同:初始化变量成为只读变量,不同生成一个新的只读变量

只读变量和常量的区别:

归纳起来:编译期间,不能直接确定初始值的const标识符,都是只读变量

    //用字面量1初始化x,x是真正意义上的常量,并且编译器会为常量x分配4个字节的空间,x会进入了符号表
    const int x = 1;
    
    //因为使用变量初始化,所以引用rx代表一个只读变量。编译器会为常量x分配4个字节的空间,rx代表这4个字节空间的别名
    const int& rx = x; //引用代表变量的别名(也就是说一段内存的别名)

引用代表变量的别名,变量的别名代表一段内存空间的别名。

const引用:

const引用使得存在的变量拥有只读属性

把const引用初始化常量,得到只读变量

    //用字面量1初始化x,x是真正意义上的常量,并且编译器会为常量x分配4个字节的空间,x会进入了符号表
    const int x = 1;
    
    //因为使用变量初始化,所以引用rx代表一个只读变量。编译器会为常量x分配4个字节的空间,rx代表这4个字节空间的别名
    const int& rx = x; //引用代表变量的别名(也就是说一段内存的别名)

    //rx代表只读变量,const_cast消除只读变量的只读属性,所以,转换后nrx是普通变量
    int& nrx = const_cast<int&>(rx);
    
    nrx = 5;//通过引用nrx,改变所对应4个字节空间的值(改变了rx和nrx)
    
    printf("x = %d\n", x);     //1 因为进入符号表,所以值不变,仍旧是1
    printf("rx = %d\n", rx);   //5 rx和nrx所引用的内存空间是一样的
    printf("nrx = %d\n", nrx); //5
   
    //编译器为const所修饰的标识符仍然分配空间,这空间一般不使用。通过引用或指针来使用
    printf("&x = %p\n", &x);     //0xbfd73668
    printf("&rx = %p\n", &rx);   //0xbfd73668
    printf("&nrx = %p\n", &nrx); //0xbfd73668

分析:C++为了兼容C语言的特性,为const所修饰的标识符仍然分配空间,只不过这个空间一般不使用。

volatile表示易变的。

    //用字面量2初始化y,但是因为volatile表示易变的,y表示只读变量
    volatile const int y = 2;
    //去除y的只读属性,用指针p指针y所对应的地址
    int* p = const_cast<int*>(&y);
    
    *p = 6;
    
    printf("y = %d\n", y);  //6
    printf("p = %p\n", p);  //0xbfd7365c

 

判别const所修饰的标识符,是不是常量的标准,编译期间确定它的值

    //y是一个变量,得到一个只读变量z
    const int z = y;
    
    p = const_cast<int*>(&z);
    
    *p = 7;
    
    printf("z = %d\n", z); //7
    printf("p = %p\n", p); //0xbfd73654

 

const引用的初始化类型不同,将得到新的只读变量

    //不同类型的变量去初始化const标识符
    char c = 'c';
    char& rc = c; //引用rc代表变量c
    //const引用的初始化类型不同(c是char,而trc是int),将得到新的只读变量
    //trc代表一个只读变量
    const int& trc = c;//char类型默认转换为int类型
    
    rc = 'a';
    
    printf("c = %c\n", c);     //a
    printf("rc = %c\n", rc);   //a
    printf("trc = %c\n", trc); //c  const引用的初始化类型不同,将得到新的只读变量!!!!

全部代码如下:

#include <stdio.h>

int main()
{
    //用字面量1初始化x,x是真正意义上的常量,并且编译器会为常量x分配4个字节的空间,x会进入了符号表
    const int x = 1;
    
    //因为使用变量初始化,所以引用rx代表一个只读变量。编译器会为常量x分配4个字节的空间,rx代表这4个字节空间的别名
    const int& rx = x; //引用代表变量的别名(也就是说一段内存的别名)

    //rx代表只读变量,const_cast消除只读变量的只读属性,所以,转换后nrx是普通变量
    int& nrx = const_cast<int&>(rx);
    
    nrx = 5;//通过引用nrx,改变所对应4个字节空间的值(改变了rx和nrx)
    
    printf("x = %d\n", x);     //1 因为进入符号表,所以值不变,仍旧是1
    printf("rx = %d\n", rx);   //5 rx和nrx所引用的内存空间是一样的
    printf("nrx = %d\n", nrx); //5
   
    //编译器为const所修饰的标识符仍然分配空间,这空间一般不使用。通过引用或指针来使用
    printf("&x = %p\n", &x);     //0xbfd73668
    printf("&rx = %p\n", &rx);   //0xbfd73668
    printf("&nrx = %p\n", &nrx); //0xbfd73668
    
    
    
  
  
  
    //用字面量2初始化y,但是因为volatile表示易变的,y表示只读变量
    volatile const int y = 2;
    //去除y的只读属性,用指针p指针y所对应的地址
    int* p = const_cast<int*>(&y);
    
    *p = 6;
    
    printf("y = %d\n", y);  //6
    printf("p = %p\n", p);  //0xbfd7365c
     
    //y是一个变量,得到一个只读变量z
    const int z = y;
    
    p = const_cast<int*>(&z);
    
    *p = 7;
    
    printf("z = %d\n", z); //7
    printf("p = %p\n", p); //0xbfd73654
    
    
    
    
   
    
    //不同类型的变量去初始化const标识符
    char c = 'c';
    char& rc = c; //引用rc代表变量c
    //const引用的初始化类型不同(c是char,而trc是int),将得到新的只读变量
    //trc代表一个只读变量
    const int& trc = c;//char类型默认转换为int类型
    
    rc = 'a';
    
    printf("c = %c\n", c);     //a
    printf("rc = %c\n", rc);   //a
    printf("trc = %c\n", trc); //c  const引用的初始化类型不同,将得到新的只读变量!!!!
    
    return 0;
}

结果如下:

 

 

 

对于引用的疑问

引用的本质就是指针常量。

指针是一个变量

  • 值为一个内存地址,不需要初始化,可以保存不同的地址
  • 通过指针可以访问对应内存地址中的值
  • 指针可以被const修饰成为常量或者只读变量

引用只是一个变量的新名字

  • 对引用的操作(赋值,取地址等)都会传递到代表的变量上,对引用的操作,就是对 对应的变量 的操作。
  • const引用使其代表的变量具有只读属性。
  • 引用必须在定义时初始化之后无法代表其他变量。

 

在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 sv = {a, b, *pc};
    
    //引用数组破坏了C语言的特性,数组的每个元素都是彼此相邻的排放
    // &array[1] - &array[0] = ? 所期望的结果是4
    //C++不支持引用数组!!!!!

    //int& array[] = {a, b, *pc}; //错误,数组的每个元素在内存里是顺序存放的,数组的地址是递增的
    
    printf("&sv.x = %p\n", &sv.x);
    printf("&sv.y = %p\n", &sv.y);
    printf("&sv.z = %p\n", &sv.z);

    //释放堆空间
    delete pc;

    return 0;
}

结果如下:

所以在C++中,不支持引用数组,因为会使得相邻数组元素的地址之差,不是我们所期望的!!!!

 

 

 

小结:

指针是一个变量。

引用是一个变量的新名字。

const引用能够生成新的只读变量。

在编译器内部使用指针常量实现“引用”

编译时不能直接确定初始值的const标识符都是只读变量

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值