C++中的static_cast, dynamic_cast和reinterpret_cast

郑重声明:本文是笔者根据个人理解所写,错误难免,欢迎拍砖!

       可以任意转载、修改,转载时是否标明出处,随君而定!

static_cast

用于“良性”和“适度良性”转换,包括不用强制转换(如自动类型转换)。static_cast全部用于明确定义的转换,包括编译器允许我们所做的不用强制转换的“安全”转换和不太安全但清楚定义的转换。

用法:static_cast < type-id > ( expression
该运算符把expression转换为type-id类型,但没有在运行时进行类型检查来保证转换的安全性。static_cast包含的类型转换包括一下几种:

A、典型的非强制变换

B、窄化(有信息丢失)变换

C、使用void*的强制变换

D、隐式类型变换

E、类层次的静态定位

  a. 向上转换是安全的,即将子类的指针或引用转换为基类
  b. 向下转换是不安全的,即将基类指针或引用转换成子类,因为是静态转换,没有在运行时进行类型检查,应使用dynamic_cast。

 1 int i = 0x7fff;  // max pos value = 32767
 2 long l = 0;
 3 float f = 1.0f;
 4 
 5 // A: typeical castless conversions:
 6 l = static_cast<long>(i);
 7 
 8 // B: narrowing conversions:
 9 i = static_cast<int>(f);
10 
11 // C: forcing a conversion from void* :
12 void* pvoid = &i;
13 float* pf = static_cast<float*>(pvoid);
14 
15 // D: Implicit type conversions, normally performed by the compiler
16 double d = 0.0;
17 int x = d; // Automatic type conversion
18 x = static_cast<int>(d);  // More explicit

 注意:static_cast不能转换掉expression的const、volitale、或者__unaligned属性。

dynamic_cast

用法:dynamic_cast < type-id > ( expression )
该运算符把expression转换成type-id类型的对象。type-id必须是类的指针、类的引用或者void *;
如果type-id是类指针类型,那么expression也必须是一个指针,如果type-id是一个引用,那么expression也必须是一个引用。

当使用dynamic_cast来试着向下类型转换一个特定的类型,仅当类型转换是争取的并且是成功的时,返回值是一个指向所需类型的指针,否则它将返回0来表示转换失败。

dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换
在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的;

在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。

 1 #include <iostream>
 2 using namespace std;
 3 
 4 class CPet { public : virtual ~CPet() {} };
 5 class CDog : public CPet {};
 6 class CCat : public CPet {};
 7 
 8 int main()
 9 {
10     CPet* pPet = new CCat; // Upcast, safe
11     // Try to cast it to CCat* :
12     CCat* pCat = dynamic_cast<CCat*>(pPet); // cast success
13     // Try to cast it to CDog* :
14     CDog* pDog = dynamic_cast<CDog*>(pPet); // cast fail
15 
16     cout << "pDog = " << (long)pDog << endl;
17     cout << "pCat = " << (long)pCat << endl;
18 }

 在上面的代码段中,将pPet向下转换为CCat*类型成功了(因为CPet* pPet = new CCat;),转换为CDog*类型失败了,说明dynamic_cast会进行类型检测。

当使用dynamic_cast时,必须对一个真正多态的层次进行操作(即它含有虚函数),这是因为dynamic_cast使用了存储在VTABLE中的信息来判断实际的类型。

注意:无论何时进行向下类型转换,我们都应该进行类型检查以确保转换是成功的(即返回值非0)。但我们不用确保指针要完全一样,因为通常在向上和向下类型转换时指针会进行调整(特别是多重继承的情况下)。

dynamic _cast运行时需要一点额外的开销,不多,但是执行大量的dynamic_cast时就说明我们的设计有问题了,也会导致性能损失。在进行向下转换时,如果我们已经明确知道是什么类型,就可以使用static_cast,以避免调用dynamic_cast产生的额外开销。比如上面的将pPet向下转换为CCat*类型,可以这样写:

CCat* pCat = static_cast<CCat*>(pPet);

reinterpret_cast

这是最不安全的一种转换机制,最有可能出问题。reinterpret_cast把对象假象为模式(为了某种隐秘的目的),仿佛它是一个完全不同的类型对象。这是低级的位模式,C因此而名称不佳。在使用reinterpret_cast做任何事之前,实际上总是需要reinterpret_cast回到原来的类型(或者把变量看做是它原来的类型)。说白了,就是将原来的类型隐藏起来,用的时候再转换回去,否则编译失败。

用法:reinterpret_casttype-id > (expression)
type-id必须是一个指针、引用、算术类型、函数指针或者成员指针。
它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,
在把该整数转换成原类型的指针,还可以得到原先的指针值)。

const_cast

const_cast用来修改类型的const或volatile属性,即可以将const转换为非const以及volatile转换为非volatile,这是const_cast唯一允许的转换。除了const 或volatile修饰之外, type_id和exdivssion的类型是一样的。
用法:const_cast< type-id > (expression)
常量指针被转化成非常量指针,并且仍然指向原来的对象;
常量引用被转换成非常量引用,并且仍然指向原来的对象;常量对象被转换成非常量对象。

Voiatile和const类试。举如下一例:

 1 class B
 2 {
 3 public:
 4     int m_iNum;
 5 }
 6 void foo()
 7 {
 8     const B b1;
 9     b1.m_iNum = 100; //comile error
10     B b2 = const_cast<B>((b1);
11     b2. m_iNum = 200; //fine
12 }

 上面的代码编译时会报错,因为b1是一个常量对象,不能对它进行改变;

使用const_cast把它转换成一个常量对象,就可以对它的数据成员任意改变。注意:b1和b2是两个不同的对象。

简单总结一下:

dynamic_cast:   通常在基类和派生类之间转换时使用;
const_cast:   主要针对const和volatile的转换.   
static_cast:   一般的转换,如果你不知道该用哪个,就用这个。   
reinterpret_cast:   用于进行没有任何关联之间的转换,比如一个字符指针转换为一个整形数。

参考资料:

http://blog.csdn.net/Lambol_8309/article/details/4534338

http://blog.sina.com.cn/s/blog_4a84e45b0100f57m.html

原文地址:https://www.cnblogs.com/520zijuan/p/2916022.html