C++有四种强制类型转换符dynamic_cast,const_cast,static_cast,reinterpret_cast的不同之处 ?
分析:C++的四种强制类型转换,所以C++不是类型安全的。分别为:static_cast , dynamic_cast , const_cast , reinterpret_cast。为什么使用C风格的强制转换可以把想要的任何东西转换成合乎心意的类型。那为什么还需要一个新的C++类型的强制转换呢?新类型的强制转换可以提供更好的控制强制转换过程,允许控制各种不同种类的强制转换。C++中风格是 static_cast<type>(content)。C++风格的强制转换其他的好处是,它们能更清晰的表明它们要干什么。程序员只要扫一眼这样的代码,就能立即知道一个强制转换的目的。
四种转换的区别:
1.static_cast:可以实现C++中内置基本数据类型之间的相互转换。int
c=
static_cast
<
int
>(7.987);
如果涉及到类的话,static_cast只能在有相互联系的类型中进行相互转换,不一定包含虚函数。
1 class A 2 {}; 3 class B:public A 4 {}; 5 class C 6 {}; 7 8 int main() 9 { 10 A* a=new A; 11 B* b; 12 C* c; 13 b=static_cast<B*>(a); // 编译不会报错, B类继承A类 14 c=static_cast<B*>(a); // 编译报错, C类与A类没有任何关系 15 return 1; 16 }
2.const_cast: 它可以使一个本来不是const类型的数据转换成const类型的,或者把const属性去掉。
3.reinterpret_cast: 有着和C风格的强制转换同样的能力。它可以转化任何内置的数据类型为其他任何的数据类型,也可以转化任何指针类型为其他的类型。它甚至可以转化内置的数据类型为指针,无须考虑类型安全或者常量的情形。不到万不得已绝对不用。
3.1reinterpret_cast(重述转换)主要是将数据从一种类型的转换为另一种类型。所谓“通常为操作数的位模式提供较低层的重新解释”也就是说将数据以 二进制存在形式的重新解释。比如:
int i; char *p = "This is a example."; i = reinterpret_cast<int>(p);
此时结果,i与p的值是完全相同的。reinterpret_cast的作用是说将指针p的值以二进制(位模式)的方式被解释为整型,并赋给i,一个明显的现象是在转换前后 没有数位损失,即一定不改变元数据。
关于reinterpret_cast,使用这个操作符的类型转换,其的转换结果几乎都是执行期定义(implementation-defined)。因此,使用reinterpret_casts的代码很 难移植。
reinterpret_casts的最普通的用途就是在函数指针类型之间进行转换。例如,假设你有一个函数指针数组:
typedef void (*FuncPtr)(); // FuncPtr是一个指向函数的指针,该函数没有参数返回值类型为void
FuncPtr funcPtrArray[10]; // funcPtrArray是一个能容纳10个FuncPtrs指针的数组
让我们假设你希望(因为某些莫名其妙的原因)把一个指向下面函数的指针存入funcPtrArray数组:
int doSomething();
你不能不经过类型转换而直接去做,因为doSomething函数对于funcPtrArray数组来说有一个错误的类型。在FuncPtrArray数组里的函数返回值是void类型,而 doSomething函数返回值是int类型。
funcPtrArray[0] = &doSomething; // 错误!类型不匹配reinterpret_cast可以让你迫使编译器以你的方法去看待它们
funcPtrArray[0] = reinterpret_cast<FuncPtr>(&doSomething); // this compiles
4.dynamic_cast:
4.1 其他三种都是编译时完成的,dynamic_cast是运行时处理的,运行时要进行类型检查。
4.2 不能用于内置的基本数据类型的强制转换。
4.3 转换如果成功的话返回的是指向类的指针或引用,转换失败的话则会返回NULL。
4.4 用dynamic_cast进行转换的,基类中一定要有虚函数,否则编译不通过。
B中需要检测有虚函数的原因:这是由于运行时类型检查需要运行时类型信息,而这个信息存储在类的虚函数表(关于虚函数表的概念,详细可见<Inside c++ object model>)中,只有定义了虚函数的类才有虚函数表。
4.5 在类的转换时,在类层次间进行上行转换时,dynamic_cast和static_cast的 效果是一样的。在进行下行转换时,dynamic_cast具有类型检查的功能,比 static_cast更安全。向上转换即为指向子类对象的向下转换,即将父类指针转化子类指针。向下转换的成功与否还与将要转换的类型有关,即要转换的指针指向的对象的实际类型与转换以后的对象类型一定要相同,否则转换失败。
参考例子:
1 #include "stdafx.h" 2 #include <iostream> 3 #include <stdlib.h> 4 #include "CSingleton.h" 5 #include<cstring> 6 using namespace std; 7 class A 8 { 9 public: 10 virtual void f() 11 { 12 cout<<"hello"<<endl; 13 }; 14 }; 15 16 class B:public A 17 { 18 public: 19 void f() 20 { 21 cout<<"hello2"<<endl; 22 }; 23 24 }; 25 26 class C 27 { 28 void pp() 29 { 30 return; 31 } 32 }; 33 34 int fun() 35 { 36 return 1; 37 } 38 39 int _tmain(int argc, _TCHAR* argv[]) 40 { 41 A* a1=new B;//a1是A类型的指针指向一个B类型的对象 42 A* a2=new A;//a2是A类型的指针指向一个A类型的对象 43 B* b; 44 C* c; 45 b=dynamic_cast<B*>(a1);//结果为not null,向下转换成功,a1之前指向的就是B类型的对象,所以可以转换成B类型的指针。 46 if(b==NULL) 47 { 48 cout<<"null"<<endl; 49 } 50 else 51 { 52 cout<<"not null"<<endl; 53 } 54 b=dynamic_cast<B*>(a2);//结果为null,向下转换失败 55 if(b==NULL) 56 { 57 cout<<"null"<<endl; 58 } 59 else 60 { 61 cout<<"not null"<<endl; 62 } 63 c=dynamic_cast<C*>(a1);//结果为null,向下转换失败 64 if(c==NULL) 65 { 66 cout<<"null"<<endl; 67 } 68 else 69 { 70 cout<<"not null"<<endl; 71 } 72 delete(a1); 73 system("pause"); 74 return 0; 75 }
输出结果为:
not null
null
null