C++中的四种类型转换符是什么(C++,开发技术)

时间:2024-05-08 08:16:42 作者 : 石家庄SEO 分类 : 开发技术
  • TAG :

一:背景

在玩 C 的时候,经常会用void*来指向一段内存地址开端,然后再将其强转成尺度更小的char*int*来丈量一段内存,参考如下代码:

intmain(){ void*ptr=malloc(sizeof(int)*10); int*int_ptr=(int*)ptr; char*char_ptr=(char*)ptr;}

由于 C 的自由度比较大,想怎么玩就怎么玩,带来的弊端就是容易隐藏着一些不易发现的bug,归根到底还是程序员的功底不扎实,C++ 设计者觉得不能把程序员想的太厉害,应该要力所能及的帮助程序员避掉一些不必要的潜在 bug,并且还要尽最大努力的避免对性能有过多的伤害,所以就出现了 4 个强制类型转换运算符。

  • const_cast

  • reinterpret_cast

  • dynamic_cast

  • static_cast

既然 C++ 做了归类,必然就有其各自用途,接下来我们逐一和大家聊一下。

二:理解四大运算符

1. const_cast

这是四个运算符中最好理解的,玩过 C++ 的都知道,默认情况下是不能修改一个 const 变量,比如下面这样:

intmain(){ constinti=10; i=12;}

这段代码肯定是要报错的,那如果我一定要实现这个功能,如何做呢?这就需要用到const_cast去掉它的常量符号,然后对 i 进行操作即可,所以修改代码如下:

intmain(){ constinti=10; autoj=const_cast<int*>(&i); *(j)=12;}

C++中的四种类型转换符是什么

2. reinterpret_cast

从名字上看就是一个重新解释转换,很显然这个非常底层,如果大家玩过 windbg ,应该知道用dt命令可以将指定的内存地址按照某一个结构体丈量出来,比如说 C# 的 CLR 在触发 GC 时,会有gc_mechanisms结构,参考代码如下:

0:000>dtWKS::gc_mechanisms0x7ffb6ba96e60coreclr!WKS::gc_mechanisms+0x000gc_index:1+0x008condemned_generation:0n0+0x00cpromotion:0n0+0x010compaction:0n1+0x014loh_compaction:0n0+0x018heap_expansion:0n0+0x01cconcurrent:0+0x020demotion:0n0+0x024card_bundles:0n1+0x028gen0_reduction_count:0n0+0x02cshould_lock_elevation:0n0+0x030elevation_locked_count:0n0+0x034elevation_reduced:0n0+0x038minimal_gc:0n0+0x03creason:0(reason_alloc_soh)+0x040pause_mode:1(pause_interactive)+0x044found_finalizers:0n0+0x048background_p:0n0+0x04cb_state:0(bgc_not_in_process)+0x050allocations_allowed:0n1+0x054stress_induced:0n0+0x058entry_memory_load:0+0x05cexit_memory_load:0

其实 reinterpret_cast 大概也是干这个事的,参考代码如下:

typedefstruct_Point{ intx; inty;}Point;intmain(){ Pointpoint={10,11}; //内存地址 void*ptr=&point; //根据内存地址丈量出Point Point*ptr_point=reinterpret_cast<Point*>(ptr); printf("x=%d",ptr_point->x);}

从代码看,我直接根据ptr地址丈量出了Point结构,说实话这个和 C 玩法就比较类似了。

3. dynamic_cast

在多态场景下,有时候会遇到这样的一个问题,一个父类有多个子类,我现在手拥一个父类,我不知道能不能将它转换为其中一个子类,要试探一下看看,那怎么去试探呢? 类似 C# 中的as运算符,在 C++ 中就需要用dynamic_cast来做这件事情,参考如下:

//点classPoint{public: Point(intx,inty):x(x),y(y){} virtualvoidshow(){}public: intx; inty;};//矩形classRectangle:publicPoint{public: Rectangle(intx,inty,intw,inth):Point(x,y),w(w),h(h){}public: intw; inth;};//三角形classTriangle:publicPoint{public: Triangle(intx,inty,intz):Point(x,y),z(z){}public: intz;};intmain(){ Point*p1=newRectangle(10,20,100,200); Point*p2=newTriangle(4,5,6); //将p1转成子类Triangle会报错的 Triangle*t1=dynamic_cast<Triangle*>(p1); if(t1==nullptr){ printf("p1不能转成Triangle"); }}

C++中的四种类型转换符是什么

对,场景就是这个,p1 其实是Rectangle转上去的, 这时候你肯定是不能将它向下转成Triangle, 问题就在这里,很多时候你并不知道此时的 p1 是哪一个子类。

接下来的一个问题是,C++ 并不像C# 有元数据,那它是如何鉴别呢? 其实这用了 RTTI 技术,哪里能看出来呢?哈哈,看汇编啦。

 Triangle*t1=dynamic_cast<Triangle*>(p1);00831D57push000831D59pushoffsetTriangle`RTTITypeDescriptor'(083C150h)00831D5EpushoffsetPoint`RTTITypeDescriptor'(083C138h)00831D63push000831D65moveax,dwordptr[p1]00831D68pusheax00831D69call___RTDynamicCast(083104Bh)00831D6Eaddesp,14h00831D71movdwordptr[t1],eax

从汇编可以看到编译器这是带夹私货了,在底层偷偷的调用了一个___RTDynamicCast函数在运行时帮忙检测的,根据cdcel调用协定,参数是从右到左,恢复成代码大概是这样。

___RTDynamicCast(&p1,0,&Point,&Triangle,0)

3. static_cast

从名字上就能看出,这个强转具有 static 语义,也就是编译阶段就生成好了,具体安全不安全,它就不管了,就拿上面的例子,将 dynamic_cast 改成 static_cast 看看有什么微妙的变化。

intmain(){ Point*p1=newRectangle(10,20,100,200); Point*p2=newTriangle(4,5,6); Triangle*t1=static_cast<Triangle*>(p1); printf("x=%d,y=%d,z=%d",t1->x,t1->y,t1->z);}

C++中的四种类型转换符是什么

我们发现居然转成功了,而且Triangle的值也是莫名奇怪,直接取了Rectangle的前三个值,如果这是生产代码,肯定要挨批了。。。

接下来简单看下汇编代码:

 Triangle*t1=static_cast<Triangle*>(p1);00DF5B17moveax,dwordptr[p1]00DF5B1Amovdwordptr[t1],eax printf("x=%d,y=%d,z=%d",t1->x,t1->y,t1->z);00DF5B1Dmoveax,dwordptr[t1]00DF5B20movecx,dwordptr[eax+0Ch]00DF5B23pushecx00DF5B24movedx,dwordptr[t1]00DF5B27moveax,dwordptr[edx+8]00DF5B2Apusheax00DF5B2Bmovecx,dwordptr[t1]00DF5B2Emovedx,dwordptr[ecx+4]00DF5B31pushedx00DF5B32pushoffsetstring"x=%d,y=%d,z=%d"(0DF8C80h)00DF5B37call_printf(0DF145Bh)00DF5B3Caddesp,10h

从代码中看,它其实就是将 p1 的首地址给了 t1,然后依次把copy偏移值+4,+8,+0C, 除了转换这个,还可以做一些 int ,long ,double 之间的强转,当然也是一样,编译时汇编代码就已经生成好了。

 </div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
本文:C++中的四种类型转换符是什么的详细内容,希望对您有所帮助,信息来源于网络。
上一篇:JavaScript编译原理是什么下一篇:

7 人围观 / 0 条评论 ↓快速评论↓

(必须)

(必须,保密)

阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18