[C++] C++风格的强制类型转换探讨

C++风格的强制类型转换:const_caststatic_castdynamic_castreinterpret_cast

使用:xxx_cast<type-id> (expression)

 

const_cast

  • 说明:该运算符用来修改类型的const或volatile属性。
 1 class TestA
 2 {
 3 public:
 4     TestA() { }
 5 public:
 6     int m_data;
 7 };
 8 
 9 void foo()
10 {
11     const TestA ta;
12     //ta1.m_data = 100;    //编译错误
13 
14     TestA *pTa = const_cast<TestA*>(&ta);
15     pTa->m_data = 200;     //OK
16     
17     TestA &taTmp = const_cast<TestA&>(ta);
18     taTmp.m_data = 300;    //OK
19 }
20 
21 int main( int argc, char * argv[] )
22 {
23     foo();
24     return 0;
25 }

 

static_cast

  • 说明:无条件强制转换,没有在运行时进行类型检查来保证转换的安全性,static_cast也不能去掉类型的const、volitale属性。
  • 场景:
  1. 基类和子类之间转换:进行上行转换(把派生类的指针或引用转换成基类表示)是安全的;进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的。
  2. 用于基本数据类型之间的转换,如把int转换成char,把int转换成enum等。
  3. 把空指针转换成目标类型的空指针。
  4. 把任何类型的表达式转换成void类型。
 1 void foo()
 2 {
 3     int n = 6;
 4     char c = static_cast<char>(n);          // 基本类型转换
 5     double d = static_cast<double>(n);
 6     float f = static_cast<float>(n);
 7     
 8     int *pn = &n;
 9     //double *d = static_cast<double*>(&n)  //无关类型指针转换,编译错误
10     void *p = static_cast<void*>(pn);       //任意类型转换成void类型
11 }
12 
13 int main( int argc, char * argv[] )
14 {
15     foo();
16     return 0;
17 }

 

dynamic_cast

  • 说明:type-id必须是类的指针、类的引用或者void*,运行时会进行类型安全检查(转换失败返回NULL)。
  • 场景:
  1. 基类和子类之间转换,上行和下行转换都是安全的。
  2. 基类必须要有虚函数。
  3. 交叉转换(相同基类的不同子类之间的转换),但结果是NULL。
 1 #include <string.h>
 2 #include <iostream>
 3 
 4 using namespace std;
 5 
 6 class BaseClass 
 7 {
 8 public:
 9     int m_data;
10     virtual void btest(){}; //基类必须有虚函数
11 };
12 
13 class DerivedClass : public BaseClass 
14 {
15 public:
16     char m_arr[100];
17     void dtest(){};
18 };
19 
20 void foo()
21 {
22     BaseClass* pb = new DerivedClass();
23     DerivedClass *pd1 = static_cast<DerivedClass *>(pb);   //子类->父类,静态类型转换,正确但不推荐
24     DerivedClass *pd2 = dynamic_cast<DerivedClass *>(pb);  //子类->父类,动态类型转换,正确
25 
26     BaseClass* pb2 = new BaseClass();
27     DerivedClass *pd3 = static_cast<DerivedClass *>(pb2);  //父类->子类,静态类型转换,危险!
28     //strcpy(pd3->m_arr, "0123456789");                    //访问子类m_arr成员越界,造成运行时错误。
29 
30     DerivedClass *pd4 = dynamic_cast<DerivedClass *>(pb2); //父类->子类,动态类型转换,安全。结果为NULL。
31     if (NULL == pd4)
32     {
33         cout << "null == pd4" << endl;
34     }
35 }
36 
37 int main( int argc, char * argv[] )
38 {
39     foo();
40     return 0;
41 }

 

reinterpret_cast

  • 说明:仅仅重新解释类型,但没有做字节对齐。
  • 场景:最普通的用途就是在函数指针类型之间进行转换,但是很难保证移植性。
 1 #include<iostream>
 2 
 3 using namespace std;
 4 
 5 class TestA
 6 {
 7 public:
 8     int m_a;
 9 };
10 
11 class TestB 
12 {
13 public:
14     int m_b;
15 };
16 
17 class TestC : public TestA, public TestB 
18 {};
19 
20 void foo()
21 {
22     TestC tc;
23 
24     cout << "&tc = 0x" << &tc << endl;
25     cout << "reinterpret_cast<TestB*>(&tc) = 0x" << reinterpret_cast<TestB*>(&tc) << endl;
26     cout << "static_cast<TestB*>(&tc) = 0x" << static_cast<TestB*>(&tc) << endl;
27 }
28 
29 int main( int argc, char * argv[] )
30 {
31     foo();
32     return 0;
33 }

结果:

static_cast转换之后结果 - reinterpret_cast转换之后的结果 = 4(即该测试类中的字节对齐长度)。

说明:static_cast在进行上行转换是安全的,static_cast计算了父子类指针转换的偏移量,并将之转换到正确的地址,而reinterpret_cast则不会做这层转换。

 

总结

  • const_cast:去const或volatile属性时用到。
  • static_cast:基本类型转换(不包括指针类型)时用到。
  • daynamic_cast:基类与子类的指针(或引用)互相转换时用到。
  • reinterpret_cast不同类型的指针类型转换(如:函数指针类型之间进行转换),慎用。

 

参考

 

(完)

posted @ 2014-01-05 21:37  helloamigo  阅读(286)  评论(0编辑  收藏  举报