C++的const_cast的问题
2015-05-28 19:45
627 查看
转自:http://blog.csdn.net/guogangj/article/details/1545119
和上一篇文章一样了,还是提起一下大约一年前我来公司面试所遇到的一道题目,题目很简单:C++有多少种cast,它们的名称和功能各是什么。(我之前的文章曾经提到过,但后来我发现自己写得并不够简明)答案如下:
一共四种cast。1、static_cast,支持子类指针到父类指针的转换,并根据实际情况调整指针的值,反过来也支持,但会给出编译警告,它作用最类似C风格的“强制转换”,一般来说可认为它是安全的;2、dynamic_cast,支持子类指针到父类指针的转换,并根据实际情况调整指针的值,和static_cast不同,反过来它就不支持了,会导致编译错误,这种转换是最安全的转换;3、reinterpret_cast,支持任何转换,但仅仅是如它的名字所描述的那样“重解释”而已,不会对指针的值进行任何调整,用它完全可以做到“指鹿为马”,但很明显,它是最不安全的转换,使用它的时候,你得头脑清醒,知道自己在干什么;4、const_cast,这个转换能剥离一个对象的const属性,也就是说允许你对常量进行修改。
这样回答即使得不了满分,拿个八九十分应该也没问题了,我后来还专门写了些测试程序来验证过,对于第一第二第三种转换都没什么问题,而const_cast却似乎不能正常工作,代码如下:
结果不是我期待的200,而是100,我一开始以为这是由于优化选项的问题,于是调整编译器选项,全部不优化,但还是一样的结果,我开始怀疑这是VC++的bug,于是使用Linux的g++来编译,结果一样,看来这和编译器没有关系,那我究竟做错了哪里呢?或者我对const_cast理解错了呢?我开始改进我的代码,我尝试不同的类型:
这次总算得到了我想要得到结果,打印出了1050,说明const_cast并没有问题,但前一个程序为什么不能正常工作?我继续尝试了不同的类型,比如char,short,float,double等,发现了规律,凡是对结构体或类进行这个转换,都是成功的,但对char,short等基本类型的转换都没有成功。我进一步改进代码,为了查看它们的值是否真的已经被修改,我使用了指针:
这次打印出来的结果是“100,101”,这就说明常量ic的值确实已经被改变了,但为什么直接打印ic就得不到正确的结果?那估计还是前边想到的“优化”的原因,可我一再确认我并没有使用优化编译选项,而且g++的表现也如此。看来只好使用最后一招了,直接查看printf究竟做了些什么,在printf处设置断点,调试程序,然后打开disassembly视图查看反汇编代码,一切真相大白。
原来虽然我没有使用优化,但系统还是对ic这个const进行了预编译般的替换,将它替换成“64h”(十六进制的64就是十进制的100),这究竟是不是C++的规范?我不知道,但我肯定这不是一般用户想要的结果,对我来说,算是个C++的bug吧。通过解决这个问题,我也学会了些东西,如果以后遇到类似这种表面上再显浅不过,但就是不能正常工作的代码片断,要学会查看反汇编代码,也许一切问题迎刃而解,另外使用const_cast的时候应该注意些什么东西,嗯,自己思考一下吧。Java没有const_cast,很多语言都没有,(我只知道C++有)既然已经被定义为常量,就是不希望它被改变,但现在又允许你改变它,这不是很可笑吗?但难道它不是C++强大又灵活的又一体现吗?不过话说回来要看你怎么用了。
和上一篇文章一样了,还是提起一下大约一年前我来公司面试所遇到的一道题目,题目很简单:C++有多少种cast,它们的名称和功能各是什么。(我之前的文章曾经提到过,但后来我发现自己写得并不够简明)答案如下:
一共四种cast。1、static_cast,支持子类指针到父类指针的转换,并根据实际情况调整指针的值,反过来也支持,但会给出编译警告,它作用最类似C风格的“强制转换”,一般来说可认为它是安全的;2、dynamic_cast,支持子类指针到父类指针的转换,并根据实际情况调整指针的值,和static_cast不同,反过来它就不支持了,会导致编译错误,这种转换是最安全的转换;3、reinterpret_cast,支持任何转换,但仅仅是如它的名字所描述的那样“重解释”而已,不会对指针的值进行任何调整,用它完全可以做到“指鹿为马”,但很明显,它是最不安全的转换,使用它的时候,你得头脑清醒,知道自己在干什么;4、const_cast,这个转换能剥离一个对象的const属性,也就是说允许你对常量进行修改。
这样回答即使得不了满分,拿个八九十分应该也没问题了,我后来还专门写了些测试程序来验证过,对于第一第二第三种转换都没什么问题,而const_cast却似乎不能正常工作,代码如下:
intmain(intargc, char* argv[]) { constintic=100; const_cast<int &>(ic)=200; printf("%d/n", ic); return0; } |
结果不是我期待的200,而是100,我一开始以为这是由于优化选项的问题,于是调整编译器选项,全部不优化,但还是一样的结果,我开始怀疑这是VC++的bug,于是使用Linux的g++来编译,结果一样,看来这和编译器没有关系,那我究竟做错了哪里呢?或者我对const_cast理解错了呢?我开始改进我的代码,我尝试不同的类型:
classCTest { public: CTest(inti){m_val = i;printf("construction [%d]/n", m_val);}; ~CTest(){printf("destruction/n");}; voidSelfAdd(){m_val++;}; intm_val; }; intmain(intargc, char* argv[]) { constCTesttest(1000); CTesttest2(1050); const_cast<CTest &>(test)= test2; printf("%d/n", test.m_val); return0; } |
这次总算得到了我想要得到结果,打印出了1050,说明const_cast并没有问题,但前一个程序为什么不能正常工作?我继续尝试了不同的类型,比如char,short,float,double等,发现了规律,凡是对结构体或类进行这个转换,都是成功的,但对char,short等基本类型的转换都没有成功。我进一步改进代码,为了查看它们的值是否真的已经被修改,我使用了指针:
intmain(intargc, char* argv[]) { constintic = 100; constint *pc=⁣ const_cast<int &>(ic)++; printf("%d,%d/n", ic, *pc); return0; } |
这次打印出来的结果是“100,101”,这就说明常量ic的值确实已经被改变了,但为什么直接打印ic就得不到正确的结果?那估计还是前边想到的“优化”的原因,可我一再确认我并没有使用优化编译选项,而且g++的表现也如此。看来只好使用最后一招了,直接查看printf究竟做了些什么,在printf处设置断点,调试程序,然后打开disassembly视图查看反汇编代码,一切真相大白。
原来虽然我没有使用优化,但系统还是对ic这个const进行了预编译般的替换,将它替换成“64h”(十六进制的64就是十进制的100),这究竟是不是C++的规范?我不知道,但我肯定这不是一般用户想要的结果,对我来说,算是个C++的bug吧。通过解决这个问题,我也学会了些东西,如果以后遇到类似这种表面上再显浅不过,但就是不能正常工作的代码片断,要学会查看反汇编代码,也许一切问题迎刃而解,另外使用const_cast的时候应该注意些什么东西,嗯,自己思考一下吧。Java没有const_cast,很多语言都没有,(我只知道C++有)既然已经被定义为常量,就是不希望它被改变,但现在又允许你改变它,这不是很可笑吗?但难道它不是C++强大又灵活的又一体现吗?不过话说回来要看你怎么用了。
相关文章推荐
- MFCC特征提取(C语言版本)
- 【学习笔记】【C语言】数据
- 九度OJ 题目1000:计算a+b
- 对C++运算符重载的作业分析
- 遇见C++ Lambda
- [C/C++]pragma comment的使用
- c++ 学习笔记(02AM)
- [C++]C++中链表的实现
- c++设计模式之代理模式
- HDOJ 1005 Number Sequence 循环数列求值 C语言实现
- C++ 窗口设计 实践项目2 个人所得税计算器
- C++内存分配与对象构造的分离
- C++内存分配与对象构造的分离
- [LeetCode] Binary Tree Preorder Traversal (非递归的先序遍历)
- 回调函数例子1(c++)
- C++文件流操作与流缓冲重定向
- 黑马程序员——c语言概述
- C++ 窗口初级 实践项目1 函数求解
- 栈的链式存储结构及简单实现
- [LeetCode] Insertion Sort List