c++中的类型转换(dynamic_cast, reinterpret_cast, static_cast ,const_cast)

在c++中提供了如下方式的类型转换:

dynamic_cast <new_type> (expression)
reinterpret_cast <new_type> (expression)
static_cast <new_type> (expression)
const_cast <new_type> (expression)

dynamic_cast

dynamic_cast只处理指针和对象的引用。其目的是确保类型转换的结果是一个有效的完整的对象。

因此,dynamic_cast总是能成功地一个类转换到它的一个基类。

class CBase { };
class CDerived: public CBase { };
CBase b; CBase* pb;
CDerived d; CDerived* pd;
pb = dynamic_cast<CBase*>(&d);     // ok: derived-to-base
pd = dynamic_cast<CDerived*>(&b);  // wrong: base-to-derived 

第二个转换是错误的,除非基类是多态(polymorphic)。

当一个类是多态,dynamic_cast在运行时会执行一个特殊检查,以确保表达式产生了一个有效的完整的对象:

// dynamic_cast
#include <iostream>
#include <exception>
using namespace std;

class CBase { virtual void dummy() {} };
class CDerived: public CBase { int a; };

int main () {
  try {
    CBase * pba = new CDerived;
    CBase * pbb = new CBase;
    CDerived * pd;

    pd = dynamic_cast<CDerived*>(pba);
    if (pd==0) cout << "Null pointer on first type-cast" << endl;

    pd = dynamic_cast<CDerived*>(pbb);
    if (pd==0) cout << "Null pointer on second type-cast" << endl;

  } catch (exception& e) {cout << "Exception: " << e.what();}
  return 0;
}

尽管两者都是指针的类型CBase *,pba指向一个CDerived类型的对象,而从CDerived指向一个CBase类型的对象。因此,当他们各自的类型铸件执行使用dynamic_cast,pba指向一个完整的CDerived类对象的类,而pbb指向一个不完整的CDerived类的对象。

兼容性注意:dynamic_cast需要运行时类型信息(RTTI)跟踪动态类型。一些编译器支持这个特性作为一个选项,默认情况下是禁用的。这必须启用运行时类型检查使用dynamic_cast正常工作。.

dynamic_cast也可以转换空指针甚至不相关的类之间的指针,也可以把任何类型的指针转换到空指针(void *)。

reinterpret_cast

reinterpret_cast可以完成从任何指针类型到任何其他指针类型的转换,甚至是不相关的类。

reinterpret_cast但不是static_cast的转换在c++是低级操作,其解释结果通常是系统相关的,因此不可移植的。

class A {};
class B {};
A * a = new A;
B * b = reinterpret_cast<B*>(a);
虽然b指向了一个不完整的对象,但是上面的语句是合法的,只不过,当b解引用可能时会产生运行时错误。

static_cast

static_cast可以执行相关类指针之间的转换,可以从派生类到基类,也可以从基类到派生类。这将确保至少类是兼容的,如果适当的对象被转换,但是在运行时没有执行安全检查,以检查是否被转换的对象实际上是一个完整的对象类型的目的地。

因此,程序员,以确保转换是安全的。但另一方面,dynamic_cast避免的类型安全检查的开销。

class CBase {};
class CDerived: public CBase {};
CBase * a = new CBase;
CDerived * b = static_cast<CDerived*>(a);
虽然b指向了一个不完整的对象,但是上面的语句是合法的,只不过,当b解引用可能时会产生运行时错误。

此外,static_cast还可以完成基本类型之间的转换。但是不能转换const, volatile__unaligned等属性。

const_cast

const_cast维护对象的常量属性,可以设置或者去掉对象的常量属性:

// const_cast
#include <iostream>
using namespace std;

void print (char * str)
{
  cout << str << endl;
}

int main () {
  const char * c = "sample text";
  print ( const_cast<char *> (c) );
  return 0;
}


typeid

typeid可以检查变量的类型,并用name()加以输出:

// typeid, polymorphic class
#include <iostream>
#include <typeinfo>
#include <exception>
using namespace std;

class CBase { virtual void f(){} };
class CDerived : public CBase {};

int main () {
  try {
    CBase* a = new CBase;
    CBase* b = new CDerived;
    cout << "a is: " << typeid(a).name() << '\n';
    cout << "b is: " << typeid(b).name() << '\n';
    cout << "*a is: " << typeid(*a).name() << '\n';
    cout << "*b is: " << typeid(*b).name() << '\n';
  } catch (exception& e) { cout << "Exception: " << e.what() << endl; }
  return 0;
}


参考:

[1]  http://www.cplusplus.com/doc/tutorial/typecasting/

[2]  http://msdn.microsoft.com/en-us/library/c36yw7x9%28v=vs.80%29.aspx






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值