【本文链接】
http://www.cnblogs.com/hellogiser/p/static_cast-dynamic_cast-const_cast-reinterpret_cast.html
【分析】
旧式风格 vs C++风格
1
2 3 4 5 6 7 |
(new_type) expression // c-style
new_type (expression) // function-style dynamic_cast <new_type> (expression) reinterpret_cast <new_type> (expression) static_cast <new_type> (expression) const_cast <new_type> (expression) |
【static_cast】
用于基本数据类型之间的转换,如把int转换成char,把int转换成enum,这种转换的安全性也要开发人员来保证。
1
2 3 4 5 6 7 8 |
// basic type cast
enum e { A = 1, B, C }; double d = 12.25; unsigned int ui = 25; char c = static_cast<char>(ui); int i = static_cast<int>(d); int j = static_cast<int>(B); double k = static_cast<double>(ui); |
用于类层次结构中基类和子类之间指针或引用的转换。(非多态类型转换,没有virtual)
- 进行上行转换(把子类的指针或引用转换成基类表示)是安全的;
- 进行下行转换(把基类指针或引用转换成子类表示)时,转换是合法的,但是由于没有动态类型检查,所以是不安全的。
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 33 34 35 36 37 38 39 40 |
/*
version: 1.0 author: hellogiser blog: http://www.cnblogs.com/hellogiser date: 2014/9/22 */ #include "stdafx.h" #include "iostream" using namespace std; class Base { public: Base(): n1(0) {} int n1; }; class Derived: public Base { public: Derived(): n2(0) {} int n2; }; void test_static_cast() { Base *p = new Base(); Derived *pb = static_cast<Derived *>(p); cout << pb->n1 << endl; // 0 ok cout << pb->n2 << endl; // -33686019 (not safe) delete p; } int main() { test_static_cast(); return 0; } |
【dynamic_cast 】
用法:dynamic_cast < type-id > ( expression )
该运算符把expression转换成type-id类型的对象。Type-id必须是类的指针、类的引用或者void *;
如果type-id是类指针类型,那么expression也必须是一个指针,如果type-id是一个引用,那么expression也必须是一个引用。
dynamic_cast主要用于具有Virtual函数类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。(多态类型转换,必须要有virtual)
- 在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的;
- 在进行下行转换时,dynamic_cast具有类型检查的功能,并且要求基类具有virtual函数,比static_cast更安全。(如果指针能够不能够正确转换,返回NULL;如果引用不能正确转换,则抛出bad_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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
/*
version: 1.0 author: hellogiser blog: http://www.cnblogs.com/hellogiser date: 2014/9/22 */ #include "stdafx.h" #include "iostream" using namespace std; class Base { public: Base(): n1(0) {} virtual void fun() { cout << "base" << endl; } int n1; }; class Derived: public Base { public: Derived(): n2(0) {} void fun() { cout << "derived" << endl; } int n2; }; void test_static_cast() { } void test_dynamic_cast() { Base *b = new Base(); Derived *d = new Derived(); Derived *pd; // dynamic-cast pd = dynamic_cast<Derived *>(b); // pd==null if (pd == NULL) { cout << "first null" << endl; // first null } else { cout << pd->n2 << endl; pd->fun(); } pd = dynamic_cast<Derived *>(d); // pd !=null if (pd == NULL) { cout << "second null" << endl; } else { cout << pd->n2 << endl; // 0 pd->fun(); // derived } delete d; delete b; } int main() { //test_static_cast(); test_dynamic_cast(); return 0; } /* first null 0 derived */ |
上述例子,如果改为static_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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
/*
version: 1.0 author: hellogiser blog: http://www.cnblogs.com/hellogiser date: 2014/9/22 */ #include "stdafx.h" #include "iostream" using namespace std; class Base { public: Base(): n1(0) {} virtual void fun() { cout << "base" << endl; } int n1; }; class Derived: public Base { public: Derived(): n2(0) {} void fun() { cout << "derived" << endl; } int n2; }; void test_static_cast() { Base *b = new Base(); Derived *d = new Derived(); Derived *pd; // static-cast pd = static_cast<Derived *>(b); // pd!=null if (pd == NULL) { cout << "first null" << endl; } else { cout << pd->n2 << endl; // not safe pd->fun(); // not safe } pd = static_cast<Derived *>(d); // pd !=null if (pd == NULL) { cout << "second null" << endl; } else { cout << pd->n2 << endl; // 0 pd->fun(); // derived } delete d; delete b; } int main() { test_static_cast(); return 0; } /* -33686019 base 0 derived */ |
由此可以看出,对于将基类指针转换为派生类指针的下行转换:
- static_cast由于不做类型检查,能够正常转换,但是转换后的指针pb指向的是一个不完整的Derived对象,访问Derived对象的成员变量,会出现随机值(-33686019),而访问虚函数fun调用的也是Base的。
- dynamic_cast做类型检查,知道不能够正常转换,因此返回NULL。
【const_cast】
const_cast:用来消除const, volatile, __unaligned属性的转换。
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
/*
version: 1.0 author: hellogiser blog: http://www.cnblogs.com/hellogiser date: 2014/9/22 */ #include "stdafx.h" #include "iostream" using namespace std; void print (char *str) { cout << str << ' '; } void test_const_cast_fun () { const char *c = "sample text"; print ( const_cast<char *> (c) ); // const cast } class CCTest { public: void setNumber( int ); void printNumber() const; private: int number; }; void CCTest::setNumber( int num ) { number = num; } void CCTest::printNumber() const { cout << "Before: " << number << endl; const_cast<CCTest *>(this)->number--; // remove const cout << "After: " << number << endl; } void test_const_cast_class() { CCTest X; X.setNumber(8); X.printNumber(); } int main() { test_const_cast_fun(); test_const_cast_class(); return 0; } /* sample text Before: 8 After: 7 */ |
【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 33 34 35 36 |
/*
version: 1.0 author: hellogiser blog: http://www.cnblogs.com/hellogiser date: 2014/9/22 */ #include "stdafx.h" #include "iostream" #include <assert.h> using namespace std; // address---> integer value void test_reinterpret_cast() { int i = 7; cout << std::hex << &i << endl; // pointer to integer unsigned int address = reinterpret_cast<unsigned int>(&i); // static_cast is an error cout << std::hex << address << ' '; // integer to pointer int *p = reinterpret_cast<int *>(address); assert(p == &i); /* int i 7 int address ABCD int *p ABCD */ } int main() { test_reinterpret_cast(); return 0; } |
在实际中的应用价值:根据地址计算唯一的Hash值。
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
/*
version: 1.0 author: hellogiser blog: http://www.cnblogs.com/hellogiser date: 2014/9/22 */ #include "stdafx.h" #include "iostream" using namespace std; // Returns a hash code based on an address unsigned short Hash( void *p ) { unsigned int val = reinterpret_cast<unsigned int>( p ); return ( unsigned short )( val ^ (val >> 16)); } void test_reinterpret_cast() { int a[20]; for ( int i = 0; i < 20; i++ ) cout << Hash( a + i ) << endl; } int main() { test_reinterpret_cast(); return 0; } /* 63876 63992 63996 63984 63988 63976 63980 63968 63972 63960 63964 63952 63956 63944 63948 63936 63940 64056 64060 64048 */ |
【参考】
http://www.cplusplus.com/doc/tutorial/typecasting/
http://blog.csdn.net/callmeback/article/details/4040583
http://www.cnblogs.com/goodcandle/archive/2009/03/17/1413907.html