[C++] C++风格的强制类型转换探讨
C++风格的强制类型转换:const_cast,static_cast,dynamic_cast,reinterpret_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属性。
- 场景:
- 基类和子类之间转换:进行上行转换(把派生类的指针或引用转换成基类表示)是安全的;进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的。
- 用于基本数据类型之间的转换,如把int转换成char,把int转换成enum等。
- 把空指针转换成目标类型的空指针。
- 把任何类型的表达式转换成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)。
- 场景:
- 基类和子类之间转换,上行和下行转换都是安全的。
- 基类必须要有虚函数。
- 交叉转换(相同基类的不同子类之间的转换),但结果是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:不同类型的指针类型转换(如:函数指针类型之间进行转换),慎用。
参考
- http://baike.baidu.com/view/1745221.htm
- http://baike.baidu.com/view/1745207.htm
- http://baike.baidu.com/view/1745213.htm
- http://baike.baidu.com/view/1263731.htm
- http://www.cnblogs.com/goodhacker/archive/2011/07/20/2111996.html
(完)