12-经典问题解析一

注:博客中内容主要来自《狄泰软件学院》,博客仅当私人笔记使用。

测试环境:Ubuntu 10.10

GCC版本:4.4.5

 

一、关于const的疑问

        const什么时候为只读变量?什么时候是常量

 

1)const常量的判别准则

       - 只有用字面量初始化的const常量才会进入符号表

         字面量:字面量是指由字母,数字等构成的字符串或者数值,它只能作为右值出现,所谓右值是指等号右边的值,如:int a=123这里的a为左值,123为右值。

      - 使用其它变量初始化的const常量仍然是只读变量(变量被修饰const后只读属性,被其它变量初始化不影响只读属性)

int a = 1;
const int b = a;

      - 被volatile修饰的const常量不会进入符号表(变量被同时修饰时只是只读变量,不能进入符号表,const只是说明变量具有只读属性)

        在编译期间不能直接确定初始值const标识符,都被作为只读变量处理。

 

2)const引用的类型与初始化变量的类型

      - 相同初始化变量成为只读变量

      - 不同生成一个新的只读变量

编程实验
const经典问题分析
12-1.cpp
#include <stdio.h>

int main()
{
    const int x = 1;	//真正意义的常量,进入符号表,有内存,只是没使用
    const int& rx = x;	//只读变量,对应的内存空间为x的,引用的本质是指针
    
    int& nrx = const_cast<int&>(rx);    //这里并没有去掉rx只读属性
    
    nrx = 5;
    
    printf("x = %d\n", x);
    printf("rx = %d\n", rx);
    printf("nrx = %d\n", nrx);
    printf("&x = %p\n", &x);		//&x = 0xbfc0911c
    printf("&rx = %p\n", &rx);	//&rx = 0xbfc0911c
    printf("&nrx = %p\n", &nrx);	//&nrx = 0xbfc0911c
    
    return 0;
}

操作:

1) 编译:g++ 12-1.cpp -o 12-1.out,打印结果:

x = 1
rx = 5    
nrx = 5    
&x = 0xbf8946e4    
&rx = 0xbf8946e4  
&nrx = 0xbf8946e4    

测试:类型转换后,修改变量数值:

#include <stdio.h>

int main()
{
    const int x = 1;	//真正意义的常量,进入符号表,有内存,只是没使用
    const int& rx = x;	//只读变量,对应的内存空间为x的,引用的本质是指针
    
    int& nrx = const_cast<int&>(rx);//这里并没有去掉rx变量本身只读属性
    
    rx = 5;    //error。不能给只读变量rx赋值
    
    nrx = 5;
    
    printf("x = %d\n", x);
    printf("rx = %d\n", rx);
    printf("nrx = %d\n", nrx);
    printf("&x = %p\n", &x);		//&x = 0xbfc0911c
    printf("&rx = %p\n", &rx);	//&rx = 0xbfc0911c
    printf("&nrx = %p\n", &nrx);	//&nrx = 0xbfc0911c

    return 0;
}

编译报错:

12-1.cpp:10:5: error: assignment of read-only reference 'rx'
    rx = 5;
错误:给只读参数'rx'赋值    

分析:

        int& nrx = const_cast<int&>(rx);并没有去掉rx变量只读属性,更像拷贝一份数据,将拷贝的数据进行类型转换后给int& nrx。

 

2) 修改代码:

#include <stdio.h>

int main()
{
    volatile const int y = 2;		//只读变量,没有进入符号表
    int* p = const_cast<int*>(&y);	//(&y)取y内存地址,然后转换成指针类型
    // y = 7; //error。不能给只读变量y赋值
    *p = 6;
    
    printf("y = %d\n", y);    
    printf("p = %p\n", p);    
    
    const int z = y;
    
    p = const_cast<int*>(&z);	//去掉const属性,(&z)取z内存地址
    
    *p = 7;
    
    printf("z = %d\n", z);    
    printf("p = %p\n", p);
 
    return 0;
}    

编译:g++ 12-1.cpp -o 12-1.out,打印结果:

y = 6
p = 0xbf95e374    
z = 7    
p = 0xbf95e378        

栈中连续定义的两个int*变量地址差4。

 

3) 修改代码:

#include <stdio.h>

int main()
{
    char c = 'c';
    char& rc = c;	    //引用c 
    const int& trc = c;	//等价==>const int* const trc这个变量一旦定义什么都不能修改。如果去掉const会报错:用表达式'char'类型,非法初始化'int&'类型参数。这里编译器进行了优化。
    
    rc = 'a';
     
    printf("c = %c\n", c);	      //a
    printf("rc = %c\n", rc);	  //a 
    printf("trc = %c\n", trc);	  //c

    return 0;
}

编译:g++ 12-1.cpp -o 12-1.out,打印结果:

c = a
rc = a
trc = c

 

二、关于引用的疑问

        引用指针有什么关系?如何理解“引用的本质就是指针常量”? 

 

1)指针是一个变量

      - 值为一个内存地址,不需要初始化,可以保存不同的地址

      - 通过指针可以访问对应内存地址中的值

      - 指针可以被const修饰成为常量或者只读变量

 

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

      - 对引用的操作(赋值,取地址等)都会传递到代表的变量上

      - const引用使其它代表的变量具有只读属性

      - 引用必须在定义时初始化,之后无法代表其它变量

 

3)从使用C++语言的角度来看

      - 引用指针没有任何的关系

      - 引用是变量的新名字,操作引用就是操作对应的变量

 

4)从C++编译器的角度来看

      - 为了支持新概念“引用”必须要有一个有效的解决方案

      - 在编译器内部,使用指针常量(T* const p)来实现“引用”

      - 因此“引用”在定义时必须初始化(p为固定值)

 

5)在工程项目开发中

      - 在进行C++编程时直接站在使用的角度看待引用,与指针毫无关系,引用就是变量的别名

      - 当对C++代码进行调试分析时,一些特殊情况,可以考虑站在C++编译器角度看待引用

 

下面的代码有问题吗?

int a = 1;
int b = 2;
int* pc = new int(3);
int& array[] = {a, b, *pc};//error

 

编程实验
引用典型问题分析
12-2.cpp
#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};
    int& array[] = {a, b, *pc}; // &array[1] - &array[0] = ?  Expected ==> 4
    //C++不支持引用数组:数组内存是递增的,但是这样引用破坏了数组结构
    //error:declaration of ‘array’ as array of references
    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;
}

操作:

1) g++ 12-2.cpp -o 12-2.out编译错误,打印结果:

12-2.cpp:17:13: error: declaration of 'array' as array of references
    int& array[] = {a, b, *pc};
错误:声明array作为数据的引用。

2) 修改代码,注释掉引用数据:

#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};
    //int& array[] = {a, b, *pc}; // &array[1] - &array[0] = ?  Expected ==> 4
    //C++不支持引用数组:数组内存是递增的,但是这样引用破坏了数组结构
    //error:declaration of ‘array’ as array of references
    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;
}

g++ 12-2.cpp -o 12-2.out编译正常,打印结果:

&sv.x = 0x804a028
&sv.y = 0xbf94eb8c
&sv.z = 0x91e8008    

 

小结:

1)指针是一个变量

2)引用是一个变量的新名字

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

4)在编译器内部使用指针常量实现“引用”(不能引用数组)

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值