【转载】C++运算符之类型转换

一、const_cast:只影响类型修饰符const,volatile
用法:const_cast<type_id>(expression)

    该运算符用来修改类型的constvolatile属性。除了constvolatile修饰之外,type_idexpression的类型是一样的。

  • 常量指针被转化成非常量指针,并且仍然指向原来的对象;
  • 常量引用被转换成非常量引用,并且仍然指向原来的对象;
  • 常量对象被转换成非常量对象。
二、static_cast
  • 用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。进行上行转换(把派生类的指针或引用转换成基类表示)是安全的;进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的。
  • 用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。
  • 把空指针转换成目标类型的空指针。
  • 把任何类型的表达式转换成void类型。
注意:static_cast不能转换掉expressionconstvolatile、或者__unaligned属性
C++中的static_cast执行非多态的转换,用于代替C中通常的转换操作。

三、reinterpret_cast:
  • 操作符修改了操作数类型,但仅仅是重新解释了给出的对象的比特模型而没有进行二进制转换。
  • 所有映射中最危险的
  • static_cast和reinterpret_cast的区别主要在于多重继承,比如

  1. <span style="font-size: 18px;">classA { public: int m_a;}; 
  2. classB { public: int m_b;}; 
  3. classC : public A, public B {};</span> 
classA { public: int m_a;};
classB { public: int m_b;};
classC : public A, public B {};

  那么对于以下代码:

  1. <span style="font-size: 18px;">C c; 
  2. printf("%p,%p, %p\r\n", &c,              
  3.                         reinterpret_cast<B*>(&c), 
  4.                         static_cast<B*>(&c)  );</span> 
C c;
printf("%p,%p, %p\r\n", &c,             
                        reinterpret_cast<B*>(&c),
                        static_cast<B*>(&c)  );

  前两个的输出值是相同的,最后一个则会在原基础上偏移4个字节,这是因为static_cast计算了父子类指针转换的偏移量,并将之转换到正确的地址(c里面有m_a, m_b,转换为B*指针后指到m_b处),而reinterpret_cast却不会做这一层转换。


四、dynamic_cast:

  • dynamic_cast运算符可以在执行期决定真正的类型。如果downcast是安全的(也就说,如果基类指针或者引用确实指向一个派生类对象)这个运算符会传回适当转型过的指针。如果downcast不安全,这个运算符会传回空指针(也就是说,基类指针或者引用没有指向一个派生类对象)。
  • 在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的;在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。
  • 进行向下类型转换时,必须是一个指向带有虚函数的类类型的指针。这是由于运行时类型检查需要运行时类型信息,而这个信息存储在类的虚函数表,只有定义了虚函数的类才有虚函数表。
  • 使用dynamic_cast要付出显著地运行开销和内存开销。
可以参考下面这个例子进行理解:

  1. <span style="font-size: 18px;">Base b; 
  2. 00291A8B  lea         ecx,[b]   
  3. 00291A8E  call        Base::Base (291131h)   
  4. Base* pb = NULL; 
  5. 00291A93  mov         dword ptr [pb],0   
  6.  
  7. Derived d; 
  8. 00291A9A  lea         ecx,[d]   
  9. 00291A9D  call        Derived::Derived (2911C7h)   
  10. Derived* pd = NULL; 
  11. 00291AA2  mov         dword ptr [pd],0   
  12.  
  13. pb = &d; 
  14. 00291AA9  lea         eax,[d]   
  15. 00291AAC  mov         dword ptr [pb],eax   
  16. pd = static_cast<Derived*>(pb); 
  17. 00291AAF  mov         eax,dword ptr [pb]   
  18. 00291AB2  mov         dword ptr [pd],eax   
  19.  
  20. pd = dynamic_cast<Derived*>(pb); 
  21. 00291AB5  push        0   
  22. 00291AB7  push        offset Derived `RTTI Type Descriptor' (29A018h)   
  23. 00291ABC  push        offset Base `RTTI Type Descriptor' (29A000h)   
  24. 00291AC1  push        0   
  25. 00291AC3  mov         eax,dword ptr [pb]   
  26. 00291AC6  push        eax   
  27. 00291AC7  call        @ILT+640(___RTDynamicCast) (291285h)   
  28. 00291ACC  add         esp,14h   
  29. 00291ACF  mov         dword ptr [pd],eax   
  30. </span> 
Base b;
00291A8B  lea         ecx,[b]  
00291A8E  call        Base::Base (291131h)  
Base* pb = NULL;
00291A93  mov         dword ptr [pb],0  

Derived d;
00291A9A  lea         ecx,[d]  
00291A9D  call        Derived::Derived (2911C7h)  
Derived* pd = NULL;
00291AA2  mov         dword ptr [pd],0  

pb = &d;
00291AA9  lea         eax,[d]  
00291AAC  mov         dword ptr [pb],eax  
pd = static_cast<Derived*>(pb);
00291AAF  mov         eax,dword ptr [pb]  
00291AB2  mov         dword ptr [pd],eax  

pd = dynamic_cast<Derived*>(pb);
00291AB5  push        0  
00291AB7  push        offset Derived `RTTI Type Descriptor' (29A018h)  
00291ABC  push        offset Base `RTTI Type Descriptor' (29A000h)  
00291AC1  push        0  
00291AC3  mov         eax,dword ptr [pb]  
00291AC6  push        eax  
00291AC7  call        @ILT+640(___RTDynamicCast) (291285h)  
00291ACC  add         esp,14h  
00291ACF  mov         dword ptr [pd],eax  



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值