C++中四种类型转换以及const_cast是否能改变常量的问题
we have four specific casting operators:dynamic_cast, reinterpret_cast, static_cast and const_cast. Their format is to follow the new type enclosed between angle-brackets (<>) and immediately after, the expression to be converted between parentheses.
dynamic_cast <new_type> (expression)
reinterpret_cast <new_type> (expression)
static_cast <new_type> (expression)
const_cast <new_type> (expression)
一、对C++中四种类型转换总结如下:
const_cast<T>(expr)
用来移除对象的常量性(cast away the constness)
const_cast一般用于指针或者引用
使用const_cast去除const限定的目的不是为了修改它的内容
使用const_cast去除const限定,通常是为了函数能够接受这个实际参数
static_cast<T>(expr)
编译器隐式执行的任何类型转换都可以由static_cast完成
当一个较大的算术类型赋值给较小的类型时,可以用static_cast进行强制转换。
可以将void*指针转换为某一类型的指针
可以将基类指针强制转换为派生类指针,但是不安全。
无法将const转化为nonconst,这个只有const_cast才可以办得到
reinterpret_cast<T>(expr)
“通常为操作数的位模式提供较低层的重新解释”也就是说将数据以二进制存在形式的重新解释。
int i;
char *p = "This is a example.";
i = reinterpret_cast<int>(p);
//此时结果,i与p的值是完全相同的。
int *ip
char *pc = reinterpret_cast<char*>(ip);
// 程序员需要记得pc所指向的真实对象是int型,并非字符串。
// 如果将pc当作字符指针进行操作,可能会造成运行时错误
// 如int len = strlen(pc);
多重继承时reinterpret_cast不安全。static_cast会根据父子类指针转换的偏移量转换到正确地址,而reinterpret_cast不会。
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
#include <cassert>
#include <iostream> using namespace std; class A class B class C: public A, public B }; int main(void) C c; cout << (void *)static_cast<B *>(&c) << endl; return 0; |
dynamic_cast<T>(expr)
执行“安全向下”转型操作,也就是说支持运行时识别指针或所指向的对象,这是唯一个无法用旧式语来进行的转型操作。
dynamic_cast可谓是最严格的转换,static_cast次之,而reinterpret_cast则是最宽松的。如果你遇到不能将整型转变为函数指针的问题,你可以这样解决:
reinterpret_cast<LPFUN&>(nAddress);
注意LPFUN这里有个“&”符号,表示引用,C++的引用其实就是用指针实现的,而这些“转换”其实都是指针的转换,所以加上引用符号编译才能通过。
二、也许大家都有过这样的疑惑:const_cast可以去除一个常量的const属性,去除const属性后应该可以对“常量”进行修改,通过调试器发现内存中的值是被改变的,可是再传递这个“常量”的时候,值却一直保持原状,实在古怪,在Windows下用VC、尝试如此,在Linux下用g++尝试也如此,我原先以为和编译器的优化选项有关系,把所有优化选项关闭,照样没用,为什么?
写了个程序进行测试:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
#include <iostream>
using namespace std; void Fun(int &value) int main(void) int *ptr = const_cast<int *>(&val); int &ref = const_cast<int &>(val); Fun(const_cast<int &>(val)); return 0; |
输出为:
可以看出打印的地址是一样的,而且奇怪的是val还是等于100,而通过*ptr打印出来的却是更改后的200,再者Fun函数打印的是300,即被引用再次修改了一次,在打印语句附近设置断点并调试反汇编,截取一段如下图:
可以明显地看出系统是对val这个const进行了预处理般的替换,将它替换成“64h”(十六进制的64就是十进制的100),即在编译生成的指令中val就已经被替换成100了,其实加const只是告诉编译器不能修改而不是真正地不可修改,如果程序员不注意而去修改了它会报错,现在我们利用const_cast去除了常量性,然后通过指针和引用对其进行了修改,所以通过指针打印或者引用传参的时候就能看出其内存确实变化了,但为了保护val这个变量本来的const特性,所以每次我们使用val时,系统都将其替换成初始值100,确保了val还是“不可变”的。记住,只有当const限定符加在已经初始化的全局变量前面的时候,此时变量处在.rodata段(linux下),才是真正的不可修改,否则通过指针都是可以修改的,虽然编译过程中会产生警告。
在linux下测试也是同样的输出结果:
附录:
MSDN上关于四种cast的说明:
reinterpret_cast Operator
The
reinterpret_cast operator allows any pointer to be converted into any
other pointer type. It also allows any integral type to be converted
into
any pointer type and vice versa. Misuse of the reinterpret_cast
operator can easily be unsafe. Unless the desired conversion is
inherently low-level, you should use one of the other cast operators.
dynamic_cast Operator
The
expression dynamic_cast( expression ) converts the operand expression
to an object of type type-id. The type-id must be a pointer or a
reference
to a previously defined class type or a“pointer
to void”.
The type of expression must be a pointer if type-id is a pointer, or an l-value if type-id is a reference.
static_cast Operator
The
expression static_cast < type-id > ( expression ) converts
expression to the type of type-id based solely on the types present in
the expression.
No run-time type check is made to ensure the safety of the conversion.
const_cast operator
The const_cast operator can be used to remove the const, volatile, and __unaligned attribute(s) from a class.
参考:http://blog.csdn.net/guogangj/archive/2007/03/29/1545119.aspx
C++的const_cast的问题
和上一篇文章一样了,还是提起一下大约一年前我来公司面试所遇到的一道题目,题目很简单:C++有多少种cast,它们的名称和功能各是什么。(我之前的文章曾经提到过,但后来我发现自己写得并不够简明)答案如下:
一共四种cast。
1、static_cast,支持子类指针到父类指针的转换,并根据实际情况调整指针的值,反过来也支持,但会给出编译警告,它作用最类似C风格的“强制转换”,一般来说可认为它是安全的;
2、dynamic_cast,支持子类指针到父类指针的转换,并根据实际情况调整指针的值,和static_cast不同,反过来它就不支持了,会导致编译错误,这种转换是最安全的转换;
3、reinterpret_cast,支持任何转换,但仅仅是如它的名字所描述的那样“重解释”而已,不会对指针的值进行任何调整,用它完全可以做到“指鹿为马”,但很明显,它是最不安全的转换,使用它的时候,你得头脑清醒,知道自己在干什么;
4、const_cast,这个转换能剥离一个对象的const属性,也就是说允许你对常量进行修改。
这样回答即使得不了满分,拿个八九十分应该也没问题了,我后来还专门写了些测试程序来验证过,对于第一第二第三种转换都没什么问题,而const_cast却似乎不能正常工作,代码如下:
int main(int argc, char* argv[])
{
const int ic=100;
const_cast<int &>(ic)=200;
printf("%d/n", ic);
return 0;
}
结果不是我期待的200,而是100,我一开始以为这是由于优化选项的问题,于是调整编译器选项,全部不优化,但还是一样的结果,我开始怀疑这是VC++的bug,于是使用Linux的g++来编译,结果一样,看来这和编译器没有关系,那我究竟做错了哪里呢?或者我对const_cast理解错了呢?我开始改进我的代码,我尝试不同的类型:
class CTest
{
public:
CTest(int i){m_val = i;printf("construction [%d]/n", m_val);};
~CTest(){printf("destruction/n");};
void SelfAdd(){m_val++;};
int m_val;
};
int main(int argc, char* argv[])
{
const CTest test(1000);
CTest test2(1050);
const_cast<CTest &>(test)= test2;
printf("%d/n", test.m_val);
return 0;
}
这次总算得到了我想要得到结果,打印出了1050,说明const_cast并没有问题,但前一个程序为什么不能正常工作?我继续尝试了不同的类型,比如char,short,float,double等,发现了规律,凡是对结构体或类进行这个转换,都是成功的,但对char,short等基本类型的转换都没有成功。我进一步改进代码,为了查看它们的值是否真的已经被修改,我使用了指针:
int main(int argc, char* argv[])
{
const int ic = 100;
const int *pc=⁣
const_cast<int &>(ic)++;
printf("%d,%d/n", ic, *pc);
return 0;
}
这次打印出来的结果是“100,101”,这就说明常量ic的值确实已经被改变了,但为什么直接打印ic就得不到正确的结果?那估计还是前边想到的“优化”的原因,可我一再确认我并没有使用优化编译选项,而且g++的表现也如此。看来只好使用最后一招了,直接查看printf究竟做了些什么,在printf处设置断点,调试程序,然后打开disassembly视图查看反汇编代码,一切真相大白。
原来虽然我没有使用优化,但系统还是对ic这个const进行了预编译般的替换,将它替换成“64h”(十六进制的64就是十进制的100),这究竟是不是C++的规范?我不知道,但我肯定这不是一般用户想要的结果,对我来说,算是个C++的bug吧。通过解决这个问题,我也学会了些东西,如果以后遇到类似这种表面上再显浅不过,但就是不能正常工作的代码片断,要学会查看反汇编代码,也许一切问题迎刃而解,另外使用const_cast的时候应该注意些什么东西,嗯,自己思考一下吧。Java没有const_cast,很多语言都没有,(我只知道C++有)既然已经被定义为常量,就是不希望它被改变,但现在又允许你改变它,这不是很可笑吗?但难道它不是C++强大又灵活的又一体现吗?不过话说回来要看你怎么用了。
C++中四种类型转换以及const_cast是否能改变常量的问题的更多相关文章
- [转]C++中四种类型转换符的总结
C++中四种类型转换符的总结 一.reinterpret_cast用法:reinpreter_cast<type-id> (expression) reinterpret_cast操 ...
- c++ --> c++中四种类型转换方式
c++中四种类型转换方式 c风格转换的格式很简单(TYPE)EXPRESSION,但是c风格的类型转换有不少缺点, 1)它可以在任意类型之间转换,比如你可以把一个指向const对象的指针转换成指向 ...
- C++中四种类型转换方式(ynamic_cast,const_cast,static_cast,reinterpret_cast)
Q:什么是C风格转换?什么是static_cast, dynamic_cast 以及 reinterpret_cast?区别是什么?为什么要注意? A:转换的含义是通过改变一个变量的类型为别的类型从而 ...
- C++中四种类型转换方式
类型转换有c风格的,当然还有c++风格的.c风格的转换的格式很简单(TYPE)EXPRESSION,但是c风格的类型转换有不少的缺点,有的时候用c风格的转换是不合适的,因为它可以在任意类型之间转换,比 ...
- 【C++】类型转换简述:四种类型转换方式的说明及应用
本文主要简述在C++中四种类型转换的方式:static_cast.reniterpret_cast.const_cast和dynamic_cast. 在介绍C++类型转换方式之前,我们先来看看C语言的 ...
- 面试问题之C++语言:说一说C++中四种cast转换
C++中四种类型转换是:static_cast.dynamic_cast.const_cast.reinterpret_cast 1.const_cast 常量转换,用于将const变量转为非cons ...
- C++语言中的四种类型转换
1 引子 这篇笔记是根据StackOverflow上面的一个问题整理而成,主要内容是对C/C++当中四种类型转换操作进行举例说明.在之前其实对它们都是有所了解的,而随着自己在进行总结,并敲了一些测试示 ...
- C++中四种强制类型转换区别详解
C++即支持C风格的类型转换,又有自己风格的类型转换.C风格的转换格式很简单,但是有不少缺点的: 1.转换太过随意,可以在任意类型之间转换.你可以把一个指向const对象的指针转换成指向非const对 ...
- [转载]C++中四种强制类型转换方式
C++中四种强制类型转换方式 原文地址:http://www.cnblogs.com/home123/p/6763967.html 类型转换有c风格的,当然还有c++风格的.c风格的转换的格式很简单( ...
随机推荐
- 给WebAPI的REST接口添加测试页面(三)
在前面的文章中,我介绍过了通过Swashbuckle在WebAPI中集成Swagger-UI.不过这种方式不适合于最新版的ASP.Net MVC6下的WebAPI,在网上搜了一下,发现了它还有一个专供 ...
- 数论E - Biorhythms(中国剩余定理,一水)
E - Biorhythms Time Limit:1000MS Memory Limit:10000KB 64bit IO Format:%I64d & %I64u Subm ...
- The Eclipse runtime options
Version 3.6 - Last revised August 5, 2009 The Eclipse platform is highly configurable. Configuration ...
- 測试oracle 11g cluster 中OLR的重要性
測试oracle 11g cluster 中OLR的重要性 called an Oracle Local Registry (OLR): each node in a cluster has a ...
- winform 取消datagridview第一行选中状态
C# WinForm 取消DataGridView的默认选中Cell 使其不反蓝 http://www.cnblogs.com/freeliver54/archive/2009/02/16/13913 ...
- GB2312简体中文编码表
GB2312简体中文编码表 code +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F A1A0 . . · ˉ ˇ ¨ " 々 — - | … ...
- JAVA加密算法(DSA)
DSA DSA-Digital Signature Algorithm 是Schnorr和ElGamal签名算法的变种,被美国NIST作为DSS(DigitalSignature Standard). ...
- Java多线程学习(吐血超具体总结)
林炳文Evankaka原创作品. 转载请注明出处http://blog.csdn.net/evankaka 写在前面的话:此文仅仅能说是java多线程的一个入门.事实上Java里头线程全然能够写一本书 ...
- 第六章 consul UI
1.建立三个consul节点(一个server+两个client) 具体的过程见http://www.cnblogs.com/java-zhao/p/5375132.html 1)在终端下启动vagr ...
- Minify压缩JS和CSS
Minify把CSS和JS压缩和削减(Minify:去掉空格回车符等),以及把多个CSS,JS文件整合到一个文件里.不要以为你的大带宽没有必要进行这类优化.使用它的理由更重要的是文件合并,而不是压缩, ...