static_cast, dynamic_cast, safe_cast c++

来源:互联网 发布:声音波形分析软件 编辑:程序博客网 时间:2024/05/29 13:43

转自:http://blog.sina.com.cn/s/blog_499386b00100dvvp.html

注:文中的一些链接已经不可访问,另,修正原文中的一段乱码,参考MSDNhttp://msdn.microsoft.com/zh-cn/library/vstudio/cby9kycs.aspx。

static_cast: includes no run-time checking, so is fast and potentially dangerous.

dynamic_cast: includes run-time checking, so is slow and safe. Returns a null pointer if the cast fails.

safe_cast: same as dynamic cast, but throws an exception if the cast fails.

以上引自:http://blog.csdn.net/xeonol/archive/2008/07/17/2667519.aspx

抛出异常毕竟是不错的,还是用safe_cast吧。  

程序静态期(static-time)  运行期(run-time)

 

msdn上的解释是:safe_cast

One example of where the compiler will not accept a static_cast but will accept a safe_cast is for casts between unrelated interface types. With safe_cast, the compiler will not issue a conversion error and will perform a check at runtime to see if the cast is possible

 
// safe_cast.cpp
// compile with: /clr
using namespace System;
interface class I1 {};
interface class I2 {};
interface class I3 {};
ref class X : public I1, public I2 {};
int main()
{
   I1^ i1 = gcnew X;
   I2^ i2 = safe_cast<I2^>(i1);   // OK, I1 and I2 have common type: X
   // I2^ i3 = static_cast<I2^>(i1);   C2440 use safe_cast instead
   try
   {
      I3^ i4 = safe_cast<I3^>(i1);   // fail at runtime, no common type
   }
   catch(InvalidCastException^)
   {
      Console::WriteLine("Caught expected exception");
   }
}
 
 

另外仔细看看:http://topic.csdn.net/t/20060820/08/4961965.html

还有这个http://hi.baidu.com/baiyw920/blog/item/6876db0f4c31f2e037d1224b.html

dynamic_cast
用法:dynamic_cast < type-id > ( expression )
       该运算符把expression转换成type-id类型的对象。Type-id必须是类的指针、类的引用或者void *;如果type-id是指针类型,那么expression也必须是一个指针;如果type-id是一个引用,那么expression必须是一个左值。
1.如果type-id是一个类指针,并且指向的类是expression的基类或间接基类,则dynamic_cast返回结果是指向type-id类的指针,该指针所指的对象是expression的部分对象。此类转换被称之为“向上映射”,因为它只是在类继承层次中向上移动指针,从子类到基类。向上映射”是一种隐式转换。
2.如果type-id是void*,则会进行运行时检查以确定expression的实际类型。返回结果是一个指向expression所指向的完整对象的指针。
3.如果type-id不是void*,则会进行运行时检查以确定expression所指向的对象是否能转换成type-id所指向的类型。
4.如果expression类型是type-id类型的基类,则进行运行时检查以确定expression是否实际指向了type-id类型的完整对象。如果的确如此,则返回结果是一个指向一个完整对象的type-id类型的指针。此类转换称之为“向下映射”,因为它在类继承层次中向下移动指针,从基类到子类。在多重继承中,会存在二义性。
5.支持交叉映射。当然在两个毫无关联的类之间进行交叉映射一般不会成功的,交叉映射一般出现在多继承中。例如:类B和类C是两个独立的类,类E同时继承了B和C。
B* pb = new E;    //pb为B类型的指针,但它指向E类型的完整对象
C* pc = dynamic_cast<C*>(pb);   //成功
上述交叉转换会成功,因为pb虽然是B类型的,但它指向E类型的完整对象,E又同时继承了B和C,所以E中也包括到了C的完整数据,所以可以实现到C类型的转换。
6.支持null值的指针转换成null值的另外类型的指针。这是交叉映射的特殊情况。一般情况下,两个毫无关联的类型之间的交叉转换不会成功,但如果要转换的值是null的话,则可以实现两种类型的指针之间的转换。

异常处理:
1.当使用dynamic_cast时,如果指定的转换不能安全进行,则会在运行时出现转换失败。如果进行的是指针类型的转换,则返回null指针;如果是引用类型的转换,则抛出bad_cast异常。
2.如果参数expression本身就没有指向一个有效的对象,则会抛出__non_rtti_object异常。

static_cast
用法:static_cast <type-id> ( expression )
       该运算符把expression转换成type-id类型的对象,该转换仅仅依赖于expression的类型。该转换不进行运行时检查,所以不确保转换的安全性。此种转换常常用于将基类指针转换成子类指针,这种转换不总是安全的。
       通常情况下,使用static_cast将数字类型如enum转换成int,或int转换成float,因为在这些转换中,数据类型都是比较明确的。static_cast映射不如dynamic_cast安全,因为它不进行运行时检查。虽然dynamic_cast比较安全,但它只是对指针和引用进行转换,并且总是进行运行时类型检查,对效率也有影响。
       static_cast和dynamic_cast都是在类继承层次上移动指针。static_cast仅依赖于映射语句提供的信息,所以是不安全的。
       在dynamic_cast映射中,它会知道expression指向的对象是否具有type-id类型所需要的完整数据,从而判断是否是安全映射;而static_cast映射只能依靠程序员添加断言来进行判断。因此,static_cast可以进行隐式转换的逆操作,但转换后的结果是不确定的,只能靠程序员来进行判断。
1.static_cast常用来进行简单数据类型间的转换而不进行类之间的转换。
2.static_cast也可用来进行任何隐式转换,包括标准转换和用户自定义的转换。
3.支持null值的指针转换成null值的另外类型的指针。
4.任何类型的expression都可显示的转换成void类型,并且转换后的void类型可任意增加const,volatile或__unaligned属性。
5.static_cast仅用于对性能要求很高,而且程序员对转换过程很清楚能保证安全转换的情况下。
6.如果要求在最后的release版本中必须使用static_cast时,那么在debug模式下用safe_cast代替它以保证成功编译。

const_cast
用法:const_cast < type-id > ( expression )
       该运算符用于移除类的const,volatile和__unaligned属性。
       指向任何对象或数据成员的指针都可以显式的转换成带有修饰符修饰的另外一种类型,但这些修饰符不包括const,volatile和__unaligned。对于指针和引用而言,转换后的结果仍是指向原来的对象。对于指向数据成员的指针来说,转换后的仍指向原来的数据成员。依赖于引用对象的类型,通过转换后的结果指针,引用,或指向数据成员的指针进行的写操作有可能出现不可预料的结果。
1.不可使用const_cast操作符直接去除一个const变量的const属性。
2.支持null值的指针转换成null值的目标类型的指针。

// compile with: /EHsc
#include <iostream>

using namespace std;
class CCTest {
public:
   void setNumber( int );
   void printNumber() const;
private:
   int number;
};

void CCTest::setNumber( int num ) { number = num; }

void CCTest::printNumber() const {
   cout << "\nBefore: " << number;
   const_cast< CCTest * >( this )->number--;
   cout << "\nAfter: " << number;
}

int main() {
   CCTest X;
   X.setNumber( 8 );
   X.printNumber();
}

       上述例子中,this在转换前是const CCTest *类型的,用const_cast转换后,this变为CCTest *类型,这样在printNumber函数中,就可改变数据成员number的值。该映射仅在它出现的地方起作用。

reinterpret_cast
用法:reinterpret_cast < type-id > ( expression )
       允许从一种指针类型转换成另外任一种指针类型。该操作符也允许任何整数类型转换成任意指针类型,反之亦然。误用reinterpret_cast操作符很容易产生不安全行为。除非要求的转换原本就是低级别的,否则应该尽量用其它的映射操作符。
1.reinterpret_cast操作符可用来从char*映射为int*,或从一种类类型指针映射到另一种毫无关联的类类型指针,但这种映射是不安全的。
2.reinterpret_cast操作符映射的结果只有将一种类型映射回它的原始类型的情况下才是安全的,其它映射在最好的情况下也是不可移植的。
3.reinterpret_cast操作符不能将const,volatile或__unaligned映射掉。
4.支持null值的指针转换成null值的目标类型的指针。
5.reinterpret_cast操作符经常用于hash函数中,如下例:

// compile with: /EHsc
#include <iostream>

// 返回一个与地址有关的hash码
unsigned short Hash( void *p ) {
   unsigned int val = reinterpret_cast<unsigned int>( p );
   return ( unsigned short )( val ^ (val >> 16));
}

using namespace std;
int main() {
   int a[20];
   for ( int i = 0; i < 20; i++ )
      cout << Hash( a + i ) << endl;
}
       reinterpret_cast操作符允许将指针看成一个整数类型。映射后的结果在进行位移位并与它自己进行异或操作从而产生一个唯一的索引值(该唯一性是指概率很高的情况下唯一)。对该索引值再用标准C映射进行截取,然后返回截取后的值。

safe_cast
用法:[cli]::safe_cast < type-id > ( expression )
     safe_cast操作符允许改变表达式的类型并产生MSIL(Microsoft 中间语言)代码。它将操作数expression转换成一个type-id类型的对象。
    编译器在大多数情况下接受static_cast类型来代替safe_cast类型。不同的是safe_cast能产生可证实的MSIL,static_cast产生的是不可证实的MSIL。     //可证实的?呵呵,有意思,就它了。
1.和static_cast一样,safe_cast调用用户定义的转换。
2.safe_cast不使用const_cast(映射掉const)。
3.safe_cast存在于cli名字空间中。
4.在两个不相关的接口类型间进行映射的情况下,编译器只接受safe_cast而不接受static_cast。使用safe_cast的时候,编译器不产生转换错误,而是在运行时进行检查判断转换是否可能进行。

// compile with: /clr
using namespace System;

interface class I1 {};
interface class I2 {};
interface class I3 {};

ref class X : public I1, public I2 {};

int main() {
   I1^ i1 = gcnew X;
   I2^ i2 = safe_cast<I2^>(i1);   // 成功,I1和I2有公共类型:X
   // I2^ i3 = static_cast<I2^>(i1);   失败,应该使用safe_cast
   try {
      I3^ i4 = safe_cast<I3^>(i1);   // 运行时失败,没有公共类型。
   }
   catch(InvalidCastException^) {
      Console::WriteLine("Caught expected exception");
   }
}


原创粉丝点击