C++ 类型转换 (const_cast/static_cast/dynamic_cast/reinterpret_cast)

                    const_cast    static_cast     dynamic_cast       reinterpret_cast

C 与 C++ 类型转换区别:

1. C风格类型转换过于粗鲁,能允许你在任何类型之间进行转换。

2. C风格的类型转换在程序语句中难以识别。在语法上类型转换由圆括号和标识符组成,而这些可以用在C++中的任何地方。

C++风格的类型转换提供了4种类型转换操作符来应对不同场合的应用。

  const_cast,字面上理解就是去const属性。

  static_cast,命名上理解是静态类型转换。如int转换成char。

  dynamic_cast,命名上理解是动态类型转换。如子类和父类之间的多态类型转换。

  reinterpreter_cast,仅仅重新解释类型,但没有进行二进制的转换。

const_cast :

1 // -- 去掉类型的const或volatile属性。
2 
3 struct SA {
4      int i;
5 };
6 const SA ra;
7 //ra.i = 10; //直接修改const类型,编译错误
8 SA &rb = const_cast<SA&>(ra);
9 rb.i = 10;

static_cast :

 
int firstNumber, secondNumber;
 ...
 // C 风格类型转换
 double result = ((double)firstNumber)/secondNumber;
 
 //C++类型转换:
 double result = static_cast(firstNumber)/secondNumber;

static_cast 在功能上基本上与C风格的类型转换一样强大,含义也一样。但它也有功能上限制。例如,你不能用static_cast象用C风格的类型转换一样把struct转换成int类型或者把double类型转换成指针类型,另外,static_cast不能从表达式中去除const属性,因为另一个新的类型转换操作符const_cast有这样的功能。

 

class Widget { ... };
class SpecialWidget: public Widget { ... };
void update(SpecialWidget *psw);

SpecialWidget sw; 
// sw 是一个非const 对象。

const SpecialWidget& csw = sw; 
// csw 是sw的一个引用,它是一个const 对象

update(&csw); 
// 错误!不能传递一个const SpecialWidget* 变量 给一个处理SpecialWidget*类型变量的函数

update(const_cast(&csw));
// 正确,csw的const被显示地转换掉(csw和sw两个变量值在update函数中能被更新)

update((SpecialWidget*)&csw);
// 同上,但用了一个更难识别的C风格的类型转换

Widget *pw = new SpecialWidget;
update(pw);
 // 错误!pw的类型是Widget*,但是update函数处理的是SpecialWidget*类型

update(const_cast(pw));
// 错误!const_cast仅能被用在影响 constness or volatileness的地方上。, 不能用在向继承子类进行类型转换。

dynamic_cast 

它被用于安全地沿着类的继承关系向下进行类型转换。这就是说,你能用dynamic_cast把指向基类的指针或引用转换成指向其派生类或其兄弟类的指针或引用,而且你能知道转换是否成功。失败的转换将返回空指针(当对指针进行类型转换时)或者抛出异常(当对引用进行类型转换时),dynamic_casts不能被用于缺乏虚函数的类型上。 

Widget *pw;
...
update(dynamic_cast(pw));
// 正确,传递给update函数一个指针,是指向变量类型为SpecialWidget的pw的指针
// 如果pw确实指向一个对象, 否则传递过去的将使空指针。

void updateViaRef(SpecialWidget& rsw);
updateViaRef(dynamic_cast(*pw));
//正确。 传递给updateViaRef函数
// SpecialWidget pw 指针,如果pw 确实指向了某个对象 否则将抛出异常

 

/* 它与static_cast相对,是动态转换。
这种转换是在运行时进行转换分析的,并非在编译时进行,明显区别于其它三个类型转换操作。
该函数只能在继承类对象的指针之间或引用之间进行类型转换。进行转换时,会根据当前运行时类型信息,判断类型对象之间的转换是否合法。dynamic_cast的指针转换失败,可通过是否为null检测,引用转换失败则抛出一个bad_cast异常。
例:*/
class Base{};
class Derived : public Base{};

//派生类指针转换为基类指针
Derived *pd = new Derived;
Base *pb = dynamic_cast<Base*>(pd);

if (!pb)
    cout << "类型转换失败" << endl;

//没有继承关系,但被转换类有虚函数
class A(virtual ~A();)   //有虚函数
class B{}:
A* pa = new A;
B* pb  = dynamic_cast<B*>(pa);

// 如果对无继承关系或者没有虚函数的对象指针进行转换、基本类型指针转换以及基类指针转换为派生类指针,都不能通过编译。

 

reinterpret_cast :

仅仅重新解释类型,但没有进行二进制的转换:

 1. 转换的类型必须是一个指针、引用、算术类型、函数指针或者成员指针。
 2. 在比特位级别上进行转换。它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,在把该整数转换成原类型的指针,还可以得到原先的指针值)。但不能将非32bit的实例转成指针。
 3. 最普通的用途就是在函数指针类型之间进行转换。
   4. 很难保证移植性。

int doSomething(){return 0;};
typedef void(*FuncPtr)();

//FuncPtr is 一个指向函数的指针,该函数没有参数,返回值类型为 void
FuncPtr funcPtrArray[10];
//10个FuncPtrs指针的数组 让我们假设你希望(因为某些莫名其妙的原因)把一个指向下面函数的指针存入funcPtrArray数组:

funcPtrArray[0] = &doSomething;
// 编译错误!类型不匹配,reinterpret_cast可以让编译器以你的方法去看待它们:funcPtrArray

funcPtrArray[0] = reinterpret_cast<FuncPtr>(&doSomething);
//不同函数指针类型之间进行转换

//基本类型指针的类型转换
double d=9.2;
double* pd = &d;
int *pi = reinterpret_cast<int*>(pd);  //相当于int *pi = (int*)pd;

//不相关的类的指针的类型转换
class A{};
class B{};
A* pa = new A;
B* pb = reinterpret_cast<B*>(pa);   //相当于B* pb = (B*)pa;

//指针转换为整数
long l = reinterpret_cast<long>(pi);   //相当于long l = (long)pi;

转换函数指针的代码是不可移植的(C++不保证所有的函数指针都被用一样的方法表示),在一些情况下这样的转换会产生不正确的结果.

 

 Refers:

http://blog.csdn.net/qychjj/article/details/4896411

http://tech.it168.com/a2011/0722/1221/000001221881_all.shtml

 

 

 

posted on 2014-03-26 16:13  舍得0215  阅读(340)  评论(0编辑  收藏  举报