类型转换操作符Cast Operators

C++ 类型转换操作符

C语言的类型转换操作有其局限性,因此C++语言增加了4个类型转换操作符。

  • reinterpret_cast
  • dynamic_cast
  • static_cast
  • const_cast

它们的语法都是一致的:

xxxx_cast < type-id > ( expression )

reinterpret_cast

对原始比特位重解释

顾名思义,reinterpret 就是重解释,reinterpret_cast 的作用就是对 expression 所表示的内容(比特位)按 type-id 类型来解释,原始数据没有任何的改变

unsigned short Hash( void* p )
{
   unsigned val = reinterpret_cast<unsigned>( p );
   return (unsigned short)(val ^ ( val >> 16 ) );
}

这里p是一个地址,在32位操作系统下这是一个32比特的数据,正好可以解释成int, 因此上面reinterpret_cast这一行作用就是将地址解释成无符号整型。

用法总结

expressiontype-id
pointerpointer
integral typepointer
pointerintegral type
  • pointer to pointer 指针到指针的转换
    允许无关类型指针的互相转换(指针类型无关性

  • integral to pointer 整型到指针的转换
    整型包括整数,bool, Enum等等都可以转换成指针

  • pointer to integral 指针到整型的转换
    需要注意的是这时候指针值有可能是32位,也有可能是64位,这时候目标整型数据需要有足够的空间能够容纳这个值。

注意点

  • MSDN文档指出对reinterpret_cast所得结果的使用是不安全的,这是指针类型无关性的特性所导致的。
  • reinterpret_cast 不能祛除 const, volatile属性。

dynamic_cast

用于多态(polymorphic)相关类型的转换
具有运行时类型检查(Run-time Type Check)的安全特性

dynamic_cast, 所谓动态转换,意味着运行时类型安全性。 当然安全是要付出代价的,代价就是运行时的类型检查。当dynamic_cast通过运行时类型检查,发现失败时,它会返回空指针或扔出 bad_cast exception。

用法总结

expressiontype-id
pointerpointer
左值reference
  • 由于dynamic_cast 适用于多态相关类型的转换,它不能使用于有基本类型或没有虚函数的自定义类型参加的场合。
  • 在转换成引用时,expression 必须是左值,因此不能是临时变量
简单多态

dynamic_cast的基本用法就是在类层次结构之间的上下转换。对于这一类的转换,唯一需要注意的是将基类指针转换成子类指针时,要注意检查转换结果,在引用的转换时要注意 catch bad_cast exception。

多重继承

多重继承时,类层次关系复杂,是使用dynamic_cast的难点。使用dynamic_cast时, 有可能出现多个基类继承自同一个上层基类的情形,考虑如下情形:

这里写图片描述

E* p = new E;
A* a = p;

此时转换会带来二义性, 因此转换失败。此时我们要做的则是多次转换:

B* b = dynamic_cast<B*>(p);
A* a = dynamic_cast<A*>(b);

当然此时由于都是上行转换,即使不使用任何转换操作符都能够成功转换。

继续!

D* d = p;

如何将指针d转换成指向A的指针?(假设我们需要得到B subobject)。

思路:

Created with Raphaël 2.1.2 D* d E* p B* b A* a

首先我们得把d 还原成指向E的指针p,再将p转换成指向B的指针b,最后得到A* a。

E* p = dynamic_cast<E*>(d);
B* b = dynamic_cast<B*>(p);
A* a = dynamic_cast<A*>(b);

这样一个简单操作竟然需要3行代码,其实dynamic_cast还有一个不为人知的特异功能,那就是交叉转换(cross cast):

B* b = dynamic_cast<B*>(d);

由于dynamic_cast运行时类型检查的特性,它可以毫不费力的将指针d转换成指向B的指针。也就是说在类层次结构中,只要转换没有二义性,dynamic_cast可以一次转换完成,所有的转换工作都由背后的运行时类型检查功能完成!但是当出现二义性的时候,则需要程序员的介入,通过多次转换消除二义性!

注意点

  • dynamic_cast 是作用于多态相关类的转换的操作符,因此不适用于基本类型或无虚函数的类型的转换。
  • 进行dynamic_cast的类型之间必须具有一定相关性,或者说在同一个类层次结构中。 当然二者之间可能并没有直接的继承关系,但可能是由于二者具有共同的子类。另一方面,在同一个类层次结构中的类,通过dynamic_cast 不一定能够转换成功。
  • 运行时类型检查确保了转换的安全性,但是一定程度上带来了额外的消耗!
  • dynamic_cast 不能祛除 const, volatile属性。
  • 由于动态运行时类型检查的额外开销会对某些资源有限的嵌入式系统带来一定压力,编译器通常会提供关闭动态类型检查的选项,此时使用dynamic_cast可能会导致编译错误!

static_cast

static_cast是传统C强制转换操作符的化身,也就是说二者的使用场合一致。

static_casttype-id 可以是任何类型,也就是说type-id可以是自定义类型,而并不一定是指针/引用。

用法总结

  • 继承关系的类型的转换
    具有继承关系的类型之间可以使用static_cast来进行转换,但是static_cast由于没有运行时类型检查,这种转换可能是不安全的。
class A {};

class B : public A {};

int main()
{
     A* a = new A;
     B* b = new B;

     A* a1 = static_cast<A*> b; //上行转换没问题
     B* b1 = static_cast<B*> a; //下行转换编译通过,但是不安全

     return 0;
}
  • 无关类型转换,编译错误。
class A{};
class B{};

B* b = new B;
A* a = static_cast<A*> (b); //编译错误
int* p = static_cast<int*>(b); //编译错误
  • 只关心表达式中type-id, expression的字面类型,不管实际类型。
B* b = dynamic_cast<B*>(d); //cross cast, ok
B* b = static_cast<B*>(d); // 编译错误,B, D不相关,即使d实际指向E

在上面讲解dynamic_cast的时候,提到dynamic_cast具有交叉转换的特异功能,显然这是由它运行时类型检查提供的功能。static_cast并不具有这种能力。

  • 基本类型的转换
    对于基本类型的转换,就不多说了。

  • 可用于用户自定义类型

class A {};

class B 
{
   B( const A& );
};

class C
{
   operator A ();
};


A a;
B b = static_cast<B>(a);  //正确,使用构造函数
B b1;
b1 = static_cast<B>(a);   //正确,使用构造函数
C c;
A a1 = static_cast<A>(c); //正确,使用转换成员函数
A a2;
a2 = static_cast<A>(c);   //正确,使用转换成员函数

显然对于用户自定义类型,static_cast是多余的,在没有使用static_cast的时候,编译器也会自动检查代码中的转换构造函数来完成转化。

我们总结一下static_cast的用法,对于继承关系的类型,大多数情况下dynamic_cast可能更安全,对于用户自定义类型,编译器会自动完成。唯独,只有基本类型的转换需要用到它,而此时这种转换其实可以使用C的强制转换操作符完成。
由此可见,C++中提供的static_cast是没有必要的,如果真要说它的用处,那就是它在C++中提供了一个选项,取代了C的强制类型转换操作符。


const_cast

用来祛除变量的const, volatile属性。

用法总结

expressiontype-id
const/volatile pointerpointer
const/volatile 左值reference

祛除了const,volatile属性之后的返回指针(或引用)还是指向原始对象,因此const_cast只适用于指针或引用。


总结

  • 只有const_cast可以用来祛除const,volatile属性。
  • 只有dynamic_cast进行运行时类型检查。
  • dynamic_cast,const_cast只能进行指针,引用转换。
  • static_cast可用于指针,引用的转换。但是也适用于基本类型之间,定义了转换构造/成员函数的自定义类之间的转换。
  • reinterpret_cast只能作用于指针和整型。它只进行低层次比特位的重新解释,但是不会修改数据。
  • 当需要在类层次中相互转换时,使用dynamic_cast
  • 当需要进行基本类型之间的转换时,使用static_cast
  • 当需要对某块内存中的内容重新解释时,可以考虑使用reinterpret_cast
  • 如果编译器提供了隐式转换,最好什么转换操作符都不要用!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值