zoukankan      html  css  js  c++  java
  • [转载]const_cast

     1. 一个经典实例

     1 /*
     2 用法:const_cast<type_id> (expression)
     3   该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外, type_id和expression的类型是一样的。
     4   一、常量指针被转化成非常量指针,并且仍然指向原来的对象;
     5   二、常量引用被转换成非常量引用,并且仍然指向原来的对象;
     6   三、常量对象被转换成非常量对象。 
     7   type_id 必须为指针或引用
     8 */
     9 class B
    10 {
    11 public:
    12     int m_iNum;
    13     B():m_iNum(50) {}
    14 };
    15 
    16 void foo()
    17 {
    18     const B *b1 = new B();
    19     //b1->m_iNum = 100; //compile error
    20     B *b2 = const_cast<B*>(b1);
    21     b2->m_iNum = 200;
    22     cout<<"b1: "<< b1->m_iNum <<endl;
    23     cout<<"b2: "<< b2->m_iNum <<endl;
    24     cout<<endl;
    25     const B b3;
    26     //b3.m_iNum = 100; //compile error
    27     B b4 = const_cast<B&>(b3);//b4 is another object
    28     b4.m_iNum = 200;
    29     cout<<"b3: "<<b3.m_iNum <<endl;
    30     cout<<"b4: "<<b4.m_iNum <<endl;
    31     cout<<endl;
    32     const B b5;
    33     //b5.m_iNum = 100; //compile error
    34     B &b6 = const_cast<B&>(b5);
    35     b6.m_iNum = 200;
    36     cout<<"b5: "<<b5.m_iNum <<endl;
    37     cout<<"b6: "<<b6.m_iNum <<endl;
    38     cout << endl;
    39     // force to convert 
    40     const int x = 50;
    41     int* y = (int *)(&x);// same address, but the content is different
    42     *y = 200;
    43     cout << "x: "<<x<<" address: "<<&x<<endl;
    44     cout << "*y: "<<*y<<" address: "<<y<<endl;
    45     cout<<endl;
    46     // int
    47     const int xx = 50;
    48     int* yy = const_cast<int *> (&xx);// same address, but the content is different
    49     *yy = 200;
    50     cout << "xx: "<<xx<<" address: "<<&xx<<endl;
    51     cout << "*yy: "<<*yy<<" address: "<<yy<<endl;
    52     cout<<endl;
    53     // int
    54     const int xxx = 50;
    55     int yyy = const_cast<int&> (xxx);// another int
    56     yyy = 200;
    57     cout << "xxx: "<<xxx<<" address: "<<&xxx<<endl;
    58     cout << "yyy: "<<yyy<<" address: "<<&yyy<<endl;
    59 }
    60 
    61 int _tmain(int argc, char* argv[])
    62 {
    63     foo();
    64     return 0;
    65 }

    result:

    b1: 200
    b2: 200


    b3: 50
    b4: 200


    b5: 200
    b6: 200


    x: 50 address: 002CF880
    *y: 200 address: 002CF880


    xx: 50 address: 002CF884
    *yy: 200 address: 002CF884


    xxx: 50 address: 002CF88C
    yyy: 200 address: 002CF888

    可以改变const 自定义类的成员变量,但是对于内置数据类型,却表现未定义行为。

    2. 关于为啥会出现同一个地址,其值却不一样的情况

    Program:
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
    const int a = 1;
    int *p = const_cast<int*>(&a);
    *p = 2;
    cout << “value a=” << a << endl;
    cout << “value *p=” << *p << endl;
    cout << “address a=” << &a << endl;
    cout << “address p=” << p << endl;
    return 0;
    }
    

      

    这个程序,从语法上看,没有任何问题(当然,这种用法不提倡 deprecated )。但是输出结果却是这样的:

    value a=1
    value *p=2
    address a=0xbfe9efb4
    address p=0xbfe9efb4(depends on machine)

    奇怪了,a和p既然指向同一块地址,为什么输出的内容却不一样呢?

    在调试的时候发现,在运行完*p=2时,调试器打出的a的地址和p是一样的,而且a和*p的内容都是2。但为什么输出时候会a=1呢?

    还是看汇编代码吧,相关部分:

    subl $8, %esp
    pushl $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
    subl $12, %esp
    //将直接数1压栈
    pushl $1
    //栈顶指针减12
    subl $12, %esp
    pushl $.LC0
    pushl $_ZSt4cout
    .LCFI7:
    //这句是”value a=”这个字符串的输出函数,char
    call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
    //栈顶指针增加20
    addl $20, %esp
    pushl %eax
    //这句是a的值输出,int
    call _ZNSolsEi
    addl $20, %esp
    pushl %eax
    .LCFI8:
    //这句是输出的endl
    call _ZNSolsEPFRSoS_E
    addl $16, %esp
    

      

    看完之后,有人会问了:怎么没看到a在哪里输出的啊,那么请你注意上面“栈顶指针增加20”这个注释,增加20之后它到哪里了?注意上面就会发现,前面有两次压栈,指针减4*2=8,一次指针减12,然后再加上20,这时候栈顶指针就到了“将直接数1压栈”下面了,显然进入输出函数后,它会从栈中找输出某个值,这里显然是数字1。

    这就是为什么会输出a=1了,因为编译器根本没去找a的值,因为a是const int型,编译器认为它的内容不会变,所以干吗非得去内存中找啊,多麻烦,直接把值放到code里输出不就行了!

    从某种意义上来说,const 相当于宏定义,但是程序为变量分配了存储空间,这样就可以进行类型检查。所以说很多 C++ 书籍作者提倡用 const 来代替 define,而且反对对 const 做 cast。就算要做 cast,也请尽量使用 C++ 的 cast 而不是 C 的类型转换。

    恶劣的编程风格会带来不可预测的后果。类型转换之类的C留下来的习惯在编写高效率的程序时候是很有用的,但一定要确保知道采用这种方式会产生什么结果再去使用。对于那些 undefined 和 deprecated 的东西可以去利用,但是脑子中一定要有 idea。

  • 相关阅读:
    Scite 编辑器及其相关项目介绍
    cmake 常用指令入门指南
    C++中的POD类型
    引用折叠、万能引用和完美转发那些事
    c++的对象初始化
    C++类对象的内存布局
    effective C++ 读书精华笔记提取
    c/c++的const说明符——深入挖掘
    gdb调试器—常用知识(一)
    g++/gcc编译器——常用知识(一)
  • 原文地址:https://www.cnblogs.com/jiayouwyhit/p/3242566.html
Copyright © 2011-2022 走看看