C++深度解析(2)—C/C++中的const分析

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_22847457/article/details/96176240

1.C语言中的const

1.1 const只读变量

  • const修饰的变量是只读的,本质还是变量
  • const修饰的局部变量在栈上分配空间
  • const修饰的全局变量在全局数据区分配空间
  • const只在编译期有用,在运行期无用
  • const修饰的变量不是真的变量,它只是告诉编译器该变量不能出现在赋值符号的左边

1.2 const全局变量的分歧

  • 在现代C语言编译器中,修改const全局变量将导致程序崩溃
  • 标准C语言编译器不会将const修饰的全局变量存储于只读存储区中,而是存储于可修改的全局数据区,其值依然可以改变。

 
 
  1. #include <stdio.h>
  2. const int g_cc = 2;
  3. int main()
  4. {
  5. const int cc = 1;
  6. int *p = ( int *)&cc;
  7. printf( "cc = %d\n", cc);
  8. *p = 3;
  9. printf( "cc = %d\n", cc);
  10. p = ( int *)&g_cc;
  11. printf( "g_cc = %d\n", g_cc);
  12. *p = 4;
  13. printf( "g_cc = %d\n", g_cc);
  14. return 0;
  15. }
  • gcc、VS2017、BCC(标准C)编译结果:

1.3 const的本质

  • C语言中的const使得变量具有只读属性
  • 现代C编译器中的const将具有全局生命周期变量存储于只读存储区(所以gcc、vs2017都会出错)
  • const不能定义真正意义上的常量

 
 
  1. #include <stdio.h>
  2. const int g_array[ 5] = { 0};
  3. void modify(int* p, int v)
  4. {
  5. *p = v;
  6. }
  7. int main()
  8. {
  9. int const i = 0;
  10. const static int j = 0;
  11. int const array[ 5] = { 0};
  12. modify(( int *)&i, 1); // ok
  13. modify(( int *)&j, 2); // error
  14. modify(( int *)& array[ 0], 3); // ok
  15. modify(( int *)&g_array[ 0], 4); // error
  16. printf( "i = %d\n", i);
  17. printf( "j = %d\n", j);
  18. printf( "array[0] = %d\n", array[ 0]);
  19. printf( "g_array[0] = %d\n", g_array[ 0]);
  20. return 0;
  21. }
  • gcc、BCC(标准C)编译结果:

1.6 const修饰函数参数和返回值

  • const修饰函数参数表示在函数体内不希望改变参数的值
  • const修饰函数返回值表示返回值不可改变,多用于返回指针的情形
  • 小贴士:C语言中的字符串字面量存储于只读存储区,在程序中需要使用  const char* 指针

 
 
  1. #include <stdio.h>
  2. const char* f(const int i)
  3. {
  4. // i = 5; //error: assignment of read-only parameter ‘i’
  5. return "Test";
  6. }
  7. int main()
  8. {
  9. const char* pc = f( 0);
  10. printf( "%s\n", pc);
  11. // pc[6] = '_'; //test.c:16:11: error: assignment of read-only location ‘*(pc + 6u)’
  12. printf( "%s\n", pc);
  13. return 0;
  14. }
  • 运行结果

1.7 小结

  • const使得变量具有只读属性
  • const不能定义真正意义上的常量
  • const将具有全局生命期的变量存储于只读存储区

2 C++中的const

2.1 编程实验 test.cpp


 
 
  1. #include <stdio.h>
  2. int main()
  3. {
  4. const int c = 0;
  5. int *p = ( int *)&c;
  6. printf( "Begin...\n");
  7. *p = 5;
  8. printf( "c = %d\n", c);
  9. printf( "*p = %d\n", *p);
  10. printf( "End...\n");
  11. return 0;
  12. }
  • vs2017运行结果:

2.2 C++中的const

  • C++在C的基础上对const进行了进化处
  • 当碰见const声明时在符号表中放入常量
  • 编译过程中若发现使用常量则直接以符号表中的值替换
  • 编译过程中若发现下述情况则给对应的常量分配空间
    • 1. 对const常量使用了extern
    • 2. 对const常量使用&操作符
  • 注意:C++编译器虽然可能为const常量分配空间,但不会使用其存储空间的值。         

  • 当遇到&c时,为其分配空间,分配空间只是为了兼容C语言
  • C语言中的const变量:C语言中const变量是只读变量,会分配存储空间
  • C++中的const常量:可能分配存储空间:
    • 当const常量为全局,并且需要在其它文件中使用
    • 当使用&操作符对const常量取地址
  • C++中的const常量类似于宏定义:const int c = 5;≈  #define c 5
  • C++中的const常量与宏定义不同
    • const常量由编译器处理,编译器对const常量进行类型检查和作用域检查
    • 宏定义由预处理器处理,单纯的文本替换

 
 
  1. #include <stdio.h>
  2. void f()
  3. {
  4. #define a 3
  5. const int b = 4; // b的作用域仅在f函数内
  6. }
  7. void g()
  8. {
  9. printf( "a = %d\n", a);
  10. //printf("b = %d\n", b); // error: 'b' was not declared in this scope
  11. }
  12. int main(int argc, char *argv[])
  13. {
  14. f();
  15. g();
  16. printf( "Press enter to continue ...");
  17. getchar();
  18. return 0;
  19. }

2.3 const常量的判别准则 

  • 只有用字面量初始化的const常量才会进入符号表 
  • 使用其它变量初始化的const常量仍然是只读变量
  • 被volatile修饰的const常量不会进入符号表 
  • 在编译期间不能直接确定初始值的const标识符,都被作为只读变量处理。
  • const引用的类型与初始化变量的类型 
    • 相同:初始化变量成为只读变量 
    • 不同:生成—个新的只读变量 

 
 
  1. #include <stdio.h>
  2. int main()
  3. {
  4. const int x = 1;
  5. const int &rx = x;
  6. int &nrx = const_cast< int &>(rx);
  7. nrx = 5;
  8. printf( "x = %d\n", x);
  9. printf( "rx = %d\n", rx);
  10. printf( "nrx = %d\n", nrx);
  11. printf( "&x = %p\n", &x);
  12. printf( "&rx = %p\n", &rx);
  13. printf( "&nrx = %p\n", &nrx);
  14. volatile const int y = 2;
  15. int* p = const_cast< int *>(&y);
  16. *p = 6;
  17. printf( "y = %d\n", y);
  18. printf( "p = %p\n", p);
  19. const int z = y;
  20. p = const_cast< int *>(&z);
  21. *p = 7;
  22. printf( "z = %d\n", z);
  23. printf( "p = %p\n", p);
  24. char c = 'c';
  25. char &rc = c;
  26. const int &trc = c; //类型不同,新的只读变量
  27. rc = 'a';
  28. printf( "c = %c\n", c);
  29. printf( "rc = %c\n", rc);
  30. printf( "trc = %c\n", trc);
  31. return 0;
  32. }
  • 运行结果

2.4 小结

  • 与C语言不同,C++中的const不是只读变量
  • C++中的const是一个真正意义上的常量
  • C++编译器可能会为const常量分配空间
  • C++完全兼容C语言中const常量的语法特性
  • 指针是—个变量 
  • 引用是一个变量的新名字 
  • const引用能够生成新的只读变量 
  • 在编译器内部使用指针常量实现“引用” 
  •  编译时不能直接确定初始值的const标识符都是只读变量

3. mutable关键字

  • mutable是为了突破const函数的限制而设计的 
  • mutable成员变量将永远处于可改变的状态 
  • mutable在实际的项目开发中被严禁滥用
  • mutable的深入分析 
    • mutable成员变量破坏了只读对象的内部状态 
    • const成员函数保证只读对象的状态不变性 
    • mutable成员变量的出现无法保证状态不变性
  • 实例分析
  • 统计对象中某个成员变量的访问次数 

 
 
  1. #include <iostream>  
  2.   
  3. using  namespace  std;  
  4.   
  5. class Test  
  6. {  
  7.      int m_value;  
  8.      mutable  int m_count;  
  9. public:  
  10.     Test( int value =  0)  
  11.     {  
  12.         m_value = value;  
  13.         m_count =  0;  
  14.     }  
  15.       
  16.      int getValue() const  
  17.     {  
  18.         m_count++;   //const成员函数,内部不能直接改变成员变量值  
  19.          return m_value;  
  20.     }  
  21.       
  22.      void setValue(int value)  
  23.     {  
  24.         m_count++;   
  25.         m_value = value;  
  26.     }  
  27.       
  28.      int getCount() const  
  29.     {  
  30.          return m_count;   
  31.     }  
  32.   
  33. };  
  34.   
  35. int main(int argc, char *argv[])  
  36. {  
  37.     Test t;  
  38.       
  39.     t.setValue( 100);  
  40.       
  41.      cout <<  "t.m_value = " << t.getValue() <<  endl;  
  42.      cout <<  "t.m_count = " << t.getCount() <<  endl;  
  43.       
  44.      const Test ct(200);  
  45.       
  46.      cout <<  "ct.m_value = " << ct.getValue() <<  endl;  
  47.      cout <<  "ct.m_count = " << ct.getCount() <<  endl;  
  48.       
  49.      return  0;  
  50. }  
  • 运行结果

  • 更好的解决方案

 
 
  1. #include <iostream>  
  2. #include <string>  
  3.   
  4. using  namespace  std;  
  5.   
  6. class Test  
  7. {  
  8.      int m_value;  
  9.      int *  const m_pCount;  
  10.      /* mutable int m_count; */  
  11. public:  
  12.     Test( int value =  0) : m_pCount( new  int( 0))  
  13.     {  
  14.         m_value = value;  
  15.          /* m_count = 0; */  
  16.     }  
  17.       
  18.      int getValue() const  
  19.     {  
  20.          /* m_count++; */     //只读对象内部不能直接改变  
  21.         *m_pCount = *m_pCount +  1;  
  22.          return m_value;  
  23.     }  
  24.       
  25.      void setValue(int value)  
  26.     {  
  27.          /* m_count++; */  
  28.         *m_pCount = *m_pCount +  1;  
  29.         m_value = value;  
  30.     }  
  31.       
  32.      int getCount() const  
  33.     {  
  34.          /* return m_count; */  
  35.          return *m_pCount;  
  36.     }  
  37.   
  38.     ~Test()  
  39.     {  
  40.          delete m_pCount;  
  41.     }  
  42. };  
  43.   
  44. int main(int argc, char *argv[])  
  45. {  
  46.     Test t;  
  47.       
  48.     t.setValue( 100);  
  49.       
  50.      cout <<  "t.m_value = " << t.getValue() <<  endl;  
  51.      cout <<  "t.m_count = " << t.getCount() <<  endl;  
  52.       
  53.      const Test ct(200);  
  54.       
  55.      cout <<  "ct.m_value = " << ct.getValue() <<  endl;  
  56.      cout <<  "ct.m_count = " << ct.getCount() <<  endl;  
  57.       
  58.      return  0;  
  59. }  

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值