类型转换操作符Cast Operators

C++ 类型转换操作符

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

它们的语法都是一致的:

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这一行作用就是将地址解释成无符号整型。

用法总结

expression type-id

pointer pointer

integral type pointer

pointer integral 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。

用法总结

expression type-id

pointer pointer

左值 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 Raphal 2.1.2D* dE* pB* bA* 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可以一次转换完成,所有的转换工作都由背后的运行时类型检查功能完成!但是当出现二义性的时候,则需要程序员的介入,通过多次转换消除二义性!

注意点static_cast

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

static_cast 的 type-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 = ;}

显然dynamic_cast更适用于这种上下行转换,因此使用static_cast进行的上下行转换并不常见。 虽然它比dynamic_cast更轻量级!

无关类型转换,编译错误。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, okB* 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的时候,编译器也会自动检查代码中的转换构造函数来完成转化。

青春一经典当即永不再赎

类型转换操作符Cast Operators

相关文章:

你感兴趣的文章:

标签云: