C++中的四种类型转换
首先C中的强制类型转换(Type Cast)很简单,不管什么类型的转换统统是: Type b = (Type)a
而C++中的四种转换类型如下:
1.static_cast 2.const_cast 3.dynamic_cast 4.reinterpret_cast.
1. static_cast<Type*> (x) 静态转换(在编译期间处理)
类似于C风格的强制转换最常用的类型转换符,在正常状况下的类型转换。主要用于C++中内置的基本数据类型之间的转换.但是没有运行时类型的检测来保证转换的安全性.
如把int转换为float,如:
int i;
float f;
f=(float)i; //c中的类型强制转换
或者f=static_cast<float>(i);
***为什么需要static_cast类型的转换?
a.用于基类和子类之间的指针或引用的转换。这种转换把子类的指针或引用转换为基类表示是安全的;
进行下行转换,把基类的指针或引用转换为子类表示时,由于没有进行动态类型检测,所以是不安全的; 简言之:子转父,安全;父转子,不安全。
b.把void类型的指针转换成目标类型的指针(不安全).
c.用于内置的基本的数据类型之间的转换.
d.把任何类型的表达式转换成void类型的.
注意:static_cast不会转换掉x的const,volatile,__unaligned属性
2. const_cast<Type*>(x)去常转换(编译时执行)
它主要作用于同一个类型之间的去常和添加常属性之间的转换.不能用做不同的类型之间的转换.它可以把一个不是常属性的转换成常属性的,同时它也可以去掉常属性.
通常用于取出const属性,把const类型的指针变为非const类型的指针,如:
const int *fun(int x,int y){}
int *ptr=const_cast<int *>(fun(2,3))
用法:const_cast<type_id> (expression)
该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外, type_id和expression的类型是一样的。
一、常量指针被转化成非常量指针,并且仍然指向原来的对象;
二、常量引用被转换成非常量引用,并且仍然指向原来的对象;
三、常量对象被转换成非常量对象。
type_id 必须为指针或引用
#include <iostream>
using namespace std;
void test( char * hello){
*hello = 'z' ;
cout << hello<<endl;
}
int main(){
const int ra = 54;
const int* w = &ra;
int* e = const_cast<int* >(&ra);
e = (int*)(&ra);
*e = 18;
cout << *e ;//输出 18
cout << ra <<endl; //输出 54 ,可以意外的发现,ra常量没有变化,难到e指向 的内存不是ra
cout << e <<endl <<&ra<<endl; // 0012FF50 0012FF50 ,但发现其地址也是相同的 ,有点小奇怪
string str("raooiang");
char * my = const_cast<char *>(str.c_str());
char * cm = "sdfsg";
//*cm = 'k' ; //访问错误
const char * mycon = "sdfesf";
const char * myc = str.c_str();
//test(const_cast<char*>(mycon));
// cout << mycon<<endl; //会出内在访问错误
test(const_cast<char*>(myc));
cout << myc <<endl; //zaooiang
cout << str.c_str() <<endl; //zaooiang ,在这里可以发现str的内容改变了
return 0;
}
const int constant = 21;
const int* const_p = &constant;
int* modifier = const_cast<int*>(const_p);
*modifier = 7;
const int constant = 21;
const int* const_p = &constant;
int* modifier = (int*)(const_p);
const int constant = 21;
int* modifier = (int*)(&constant);
const int constant = 21;
int* modifier = const_cast<int*>(&constant);
我们不能对constant进行修改,但是我们可以对modifier进行重新赋值
cout << "constant: "<< constant <<endl;
cout << "const_p: "<< *const_p <<endl;
cout << "modifier: "<< *modifier <<endl;
/**
constant: 21
const_p: 7
modifier: 7
**/
constant还是保留了它原来的值。
可是它们的确指向了同一个地址呀:
cout << "constant: "<< &constant <<endl;
cout << "const_p: "<< const_p <<endl;
cout << "modifier: "<< modifier <<endl;
/**
constant: 0x7fff5fbff72c
const_p: 0x7fff5fbff72c
modifier: 0x7fff5fbff72c
**/
3. dynamic_cast<Type*>(x)动态类型转换/向下安全转型(运行时执行)
通常用于基类和派生类之间的转换. 运行时检查该转换是否类型安全。但只在多态类型时合法,即该类至少具有一个虚拟方法。
注意:
a. 不能用于内置的基本数据类型之间的转换.
b. dynamic_cast转换成功的话返回的是类的指针或引用,失败返回null。相同基类不同子类之间的交叉转换,但结果是NULL。
c. dynamic_cast进行的转换的时候基类中一定要有虚函数,因为只有类中有了虚函数,才说明它希望让基类指针或引用指向其派生类对象的情况,这样才有意义.这是由于运行时类型检查需要运行时类型的信息,而这些信息存储在虚函数表中.
d. 在类的转换时,在类层次间进行转换的时候,dynamic_cast和static_cast进行上行转换
的时候效果是一样的;但是在进行下行转换的时候,dynamic_cast会进行类型检查所以
它更安全.它可以让指向基类的指针转换为指向其子类的指针或是其兄弟类的指针;
例如:
class C
{
//…C没有虚拟函数
};
class T{
//…
}
int main()
{
dynamic_cast<T*> (new C);//错误
}
此时如改为以下则是合法的:
class C
{
public:
virtual void f() {};// C现在是多态
}
4.reinterpret_cast<Type*>(x)重解释类型转换
reinterpret即为重新解释,此标识符的意思即为数据的二进制形式重新解释,但是不改变其值。 它有着和C风格强制类型转换同样的功能;它可以转化任何的内置数据类型为其他的类型, 同时它也可以把任何类型的指针转化为其他的类型;它的机理是对二进制数据进行重新的的解释,不会改变原来的格式,而static_cast会改变原来的格式。最普通的用途就是在函数指针类型之间进行转换。
例如:
int i;
char *ptr="hello freind!";
i=reinterpret_cast<int>(ptr);这个转换方式很少使用。
又如:
void* Data;
int* inter = reinterpret_cast<int*>(Data);
用法:
- 从指针类型到一个足够大的整数类型
- 从整数类型或者枚举类型到指针类型
- 从一个指向函数的指针到另一个不同类型的指向函数的指针
- 从一个指向对象的指针到另一个不同类型的指向对象的指针
- 从一个指向类函数成员的指针到另一个指向不同类型的函数成员的指针
- 从一个指向类数据成员的指针到另一个指向不同类型的数据成员的指针
不过事实上reinterpret_cast的使用并不局限在上边所说的几项的,任何类型的指针之间都可以互相转换,都不会得到编译错误。上述列出的几项,可能 是Linux下reinterpret_cast使用的限制,也可能是IBM推荐我们使用reinterpret_cast的方式
所以总结来说:reinterpret_cast用在任意指针(或引用)类型之间的转换;以及指针与足够大的整数类型之间的转换;从整数类型(包括枚举类型)到指针类型,无视大小。
(所谓"足够大的整数类型",取决于操作系统的位数,如果是32位的操作系统,就需要整形(int)以上的;如果是64位的操作系统,则至少需要长整形(long)。具体大小可以通过sizeof运算符来查看)。
总结:
去const属性用const_cast。
基本类型转换用static_cast。
多态类之间的类型转换用daynamic_cast。
不同类型的指针类型转换用reinterpreter_cast。
explicit修饰的变量不可以进行隐式转换类型
参考:http://blog.csdn.net/hrbeuwhw/article/details/7884797 , http://www.cnblogs.com/ider/archive/2011/07/30/cpp_cast_operator_part3.html