0
点赞
收藏
分享

微信扫一扫

const 使用小结

is2120@
 1. 修饰变量,使得在初始化变量值后不能在修改其值。
 // 无const修饰
 int  x = 4;
 x = 10;

 // 有const修饰
 const int x = 2;
 x = 10; // err

2. const替代#define的好处
 在调试时可以看见变量名,而#define后调试时只能看见值
 避免了宏定义带来的种种麻烦(宏是直接的文本替代,这会带来问题)

3. const 和指针
 const int x;      // constant int
 x = 2;            //x 非法--不能修改x

 const int* pX;    // 一个指向const int的指针,指针值可变
 *pX = 3;          //x 不能使用px修改一个const int的值
 pX = &someOtherIntVar;      // 但是px可以指向其他的地方

 int* const pY;              // 指针为const,其所指向的值类型为int
 *pY = 4;                    // 使用pY修改int的值
 pY = &someOtherIntVar;      //x 不能指向其他地方

 const int* const pZ;        // const指针,指向const变量
 *pZ = 5;                    //x
 pZ = &someOtherIntVar;      //x

4. const、指针和类型转换
 int y;
 //z 此处const的含义是:并不是说指向的变量必须是const,而是说你不能使用该指针来变更其指向的值
 const int* pConstY = &y;  //x 不能使用pConstY来修改y
 int* pMutableY = &y;      //x 能使用pMutableY来修改y
 *pMutableY = 42;

5. c++中不允许轻易绕过const属性
 赋值操作符不能没有经过明确的抓换而将一个const int * 转换成int *
 c++不支持将一个const type 类型的变量转换成为type类型的标准转换。
 const int x;             // x不可修改

 const int* pX = &x;

 *pX = 4;                 //x 错误

 int* pInt;       // 一般类型的指针(非const)
 pInt = pX;       //x 错误,不能将一个const int * 指针转换成为 int *

 int *pInt;   // 
 pInt = &x;   // 错误,不能将const int* 转换成 int *

6. 强制编译器进行类型转换(const type -> type)
 const int x = 4;
 const int* pX = &x;

 cout << x << endl;

 // 强制将 px 由 const int* 转换成 int *
 int* pX2 = (int *)pX;
 *pX2 = 3;                  //错--结果是未定义的(UB)

 cout << x << endl;        //

 上述代码在vc中所产生的会变代码
 ASSEMBLER OUTPUT                       C++ CODE
 Mov   eax, DWORD PTR _pX$[ebp]         int* pX2 = (int *)pX;
 Mov   DWORD PTR _pXX$[ebp], eax
 Mov   eax, DWORD PTR _pXX$[ebp]        *pX2 = 3;
 Mov   DWORD PTR [eax], 3
 Push  OFFSET FLAT:?endl@@.........     cout << x << endl;
 Push  4

 注意到这里的PUSH 4,即编译器觉得你定义了一个const变量,在使用的时候就没有解引用而直接引用其值了(优化的结果)。

7. const_cast 操作符
 使用 const_cast 去除变量的常量性。
 const int x = 4;      //
 const int* pX = &x;   //

 cout << x << endl;    // prints "4"

 int* pX2 = const_cast < int* > (pX);   // 将pX显式转换成非const

 *pX2 = 3;           // 未定义(BH)
 cout << x << endl;   // 
 同c style的强制类型转换不同的是,const_cast 只会改变变量的常量性,而不会改变变量的类型。

8. const 存储与字符常量
 char* szMyString = "Hello world."; // 定义了一个字符常量
 szMyString[3] = 'q';         // 未定义,试图修改静态缓冲区
 标准认为这些字符常量的类型是const,一个字符常量的类型是一个const chars的数组。

 c++中不能将一个const type标准转换为 type 类型。
    const char constArray[] = { 'H', 'e', 'l', 'l', 'o', '/0' };
    char nonConstArray[] = { 'H', 'e', 'l', 'l', 'o', '/0' };
    char* pArray = constArray;            // illegal
    char* pArray = nonConstArray;         // legal
 但是这样又是可以的
    // should be illegal - converts array of 6 const char to char*
    char* pArray = "Hello";
 这是为了和旧式的c代码兼容

9. 同样的字符常量可能指向同一个内存区域
 "The /GF option causes the compiler to pool strings and place them in read-only memory. 

 例如以下代码
 #include <stdio.h>

 int main()
 {
    char* szFirst = "Literal String";
    char* szSecond = "Literal String";

    szFirst[3] = 'q';
    printf("szFirst (%s) is at %d, szSecond (%s) is at %d/n",
          szFirst, szFirst, szSecond, szSecond);

    return 0;
 }
 在启用“string pooling”后,其输出为
 szFirst (Litqral String) is at 4266616, szSecond (Litqral String) is at 4266616
 (我这里是运行错误)

10. 总是使用 const 
 class Person
 {
    public:
       Person(char* szNewName)
       {
          // make a copy of the string
          m_szName = _strdup(szNewName);
       };

       ~Person() { delete[] m_szName; };

       const char* const GetName() const
       {
          return m_szName;
       };

    private:
       
       char* m_szName; 
 };


 在返回指针、使用指针作为参数时,总是想想是否适用const。
 这样会使得编程变得比较轻松。

11. const 成员函数
 const成员函数:该函数不会修改函数成员并且不会调用非const成员函数。
 const 或者 non-const 对象都可以调用 const 成员函数
 const对象不能调用non-const成员函数

12. The Mutable Storage Specifier
  A mutable member variable can be modified even by const member functions. 
 即便是一个const 成员函数也能修改一个 mutable 成员变量。
 class MyData
 {
    public:
       /*
       the first time, do calculation, cache result in m_lCache, and set
       m_bCacheValid to true. In subsequent calls, if m_bCacheValid is true
       then return m_lCache instead of recalculating
       */

       long ExpensiveCalculation() const
       {
          if (false == m_bCacheValid)
          {
             m_bCacheValid = true;
             m_lCache = ::SomeFormula(m_internalData);
          }
          return m_lCache;
       };

       // change data and set m_bCacheValid to false to force recalc next time
       void ChangeData()
       {
       };

    private:

       data m_internalData;
       mutable long m_lCache;
       mutable bool m_bCacheValid;
             
 };is2120

举报

相关推荐

0 条评论