static_cast
用法:static_cast < type-id > ( expression )
该运算符把expression转换为type-id类型,但没有运行时类型检查来保证转换的安全性。它主要有如下几种用法:
①用于类层次结构中基类和子类之间指针或引用的转换。
进行上行转换(把子类的指针或引用转换成基类表示)是安全的;
进行下行转换(把基类指针或引用转换成子类表示)时,由于没有动态类型检查,所以是不安全的。
②用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。
③把空指针转换成目标类型的空指针。
④把任何类型的表达式转换成void类型。
注意:static_cast不能转换掉expression的const、volitale、或者__unaligned属性。
C++中static_cast和reinterpret_cast的区别
C++primer第五章里写了编译器隐式执行任何类型转换都可由static_cast显示完成;reinterpret_cast通常为操作数的位模式提供较低层的重新解释
1、C++中的static_cast执行非多态的转换,用于代替C中通常的转换操作。因此,被做为隐式类型转换使用。比如:
int i;
float f = 166.7f;
i = static_cast<int>(f);
此时结果,i的值为166。
2、C++中的reinterpret_cast主要是将数据从一种类型的转换为另一种类型。所谓“通常为操作数的位模式提供较低层的重新解释”也就是说将数据以二进制存在形式的重新解释。比如:
int i;
char *p = "This is aexample.";
i =reinterpret_cast<int>(p);
此时结果,i与p的值是完全相同的。reinterpret_cast的作用是说将指针p的值以二进制(位模式)的方式被解释为整型,并赋给i,一个明显的现象是在转换前后没有数位损失。
reinterpret_cast
reinterpret_cast是C++里的强制类型转换符。
操作符修改了操作数类型,但仅仅是重新解释了给出的对象的比特模型而没有进行二进制转换。
例如:int *n= new int ;
double *d=reinterpret_cast<double*> (n);
在进行计算以后, d包含无用值.这是因为 reinterpret_cast仅仅是复制
n的比特位到 d,
没有进行必要的分析。
因此,需要谨慎使用 reinterpret_cast.
并且:reinterpret_cast只能在指针之间转换。
static_cast 与 reinterpret_cast
reinterpret_cast是为了映射到一个完全不同类型的意思,这个关键词在我们需要把类型映射回原有类型时用到它。我们映射到的类型仅仅是为了故弄玄虚和其他目的,这是所有映射中最危险的。(这句话是C++编程思想中的原话)
static_cast 和reinterpret_cast操作符修改了操作数类型。它们不是互逆的; static_cast在编译时使用类型信息执行转换,在转换执行必要的检测(诸如指针越界计算,类型检查).其操作数相对是安全的。另一方面;reinterpret_cast仅仅是重新解释了给出的对象的比特模型而没有进行二进制转换,例子如下:
int n=9; double d=static_cast < double > (n);
上面的例子中,我们将一个变量从 int转换到 double。这些类型的二进制表达式是不同的。要将整数
9转换到双精度整数 9,static_cast需要正确地为双精度整数
d补足比特位。其结果为 9.0。而reinterpret_cast的行为却不同:
int n=9;
double d=reinterpret_cast<double & > (n);
这次,结果有所不同.在进行计算以后, d
包含无用值.
这是因为 reinterpret_cast仅仅是复制 n的比特位到 d,
没有进行必要的分析.
因此,你需要谨慎使用 reinterpret_cast.
注意:static_cast不能转换掉expression的const、volitale、或者__unaligned属性。
dynamic_cast<>
/*这是从网上摘下的例子,主要讲述了dynamic_cast<> 的使用方法。*/
/*
作用:将一个基类对象指针(或引用)cast到继承类指针,dynamic_cast会根据基类指针是否真正指向继承类指针来做相应处理,
即会作一定的判断。
对指针进行dynamic_cast,失败返回null,成功返回正常cast后的对象指针;
对引用进行dynamic_cast,失败抛出一个异常,成功返回正常cast后的对象引用。
注意:dynamic_cast在将父类cast到子类时,父类必须要有虚函数。例如在下面的代码中将CBasic类中的test函数不定义成virtual时,编译器会报错:error C2683:dynamic_cast : “CBasic”不是多态类型
对编译器的要求:
dynamic_cast<> 会用到RTTI技术,因此需要启动“运行时类型信息”这一选项,而在VC.net 2003中默认是关闭的。
所以需要人为的启动这一选项,否则编译器会报下面的警告:
warningC4541: “dynamic_cast”用在了带 /GR- 的多态类型“CBasic”上;
可能导致不可预知的行为从而导致程序在运行时发生异常。
该设置在Project->Setting中 C/C++ -> C++ Language中设置。
*/
#include <iostream>
using namespace std;
class CBasic
{
public:
virtual inttest(){return 0;} // 一定要是 virtual
};
class CDerived : public CBasic
{
public:
virtual int test(){ return 1;}
};
int main()
{
CBasic cBasic;
CDerived cDerived;
CBasic * pB1 = new CBasic;
CBasic * pB2 = new CDerived;
//dynamic castfailed, so pD1 is null.
CDerived * pD1 =dynamic_cast<CDerived * > (pB1);
//dynamic castsucceeded, so pD2 points to CDerivedobject
CDerived * pD2 =dynamic_cast<CDerived * > (pB2);
//dynamci castfailed, so throw an exception.
// CDerived & rD1 =dynamic_cast<CDerived &> (*pB1);
//dynamic cast succeeded, so rD2 references to CDerived object.
CDerived & rD2 =dynamic_cast<CDerived &> (*pB2);
return 0;
}
const_cast<>
/*
用法:const_cast<type_id> (expression)
该运算符用来修改类型的const或volatile属性。除了const或volatile修饰之外,type_id和expression的类型是一样的。
一、常量指针被转化成非常量指针,并且仍然指向原来的对象;
二、常量引用被转换成非常量引用,并且仍然指向原来的对象;
三、常量对象被转换成非常量对象。
type_id 必须为指针或引用
*/
可以改变const 自定义类的成员变量,但是对于内置数据类型,却表现未定义行为
class B
{
public:
int m_iNum;
B():m_iNum(50) {}
};
void foo()
{
const B *b1 = new B();
//b1->m_iNum = 100; //compile error
B *b2 = const_cast<B*>(b1); // const_cast作用:去掉const //注意:没给b2开辟空间,b1,b2指向相同空间
b2->m_iNum = 200;
cout<<"b1: "<< b1->m_iNum<<endl; //result:200 b1,b2指向相同空间
cout<<"b2: "<< b2->m_iNum<<endl; //result:200
cout<<endl;
const B b3;
//b3.m_iNum = 100; //compile error
B b4 = const_cast<B&>(b3); //b4 is another object
b4.m_iNum = 200;
cout<<"b3: "<<b3.m_iNum<<endl; //result:50
//3个例子中唯一将类对象const A经const_cast转换成另一个对象 (非const) B的
cout<<"b4: "<<b4.m_iNum<<endl; //result:200
cout<<endl;
const B b5;
//b5.m_iNum = 100; //compile error
B &b6 = const_cast<B&>(b5); //b6是b5的别称,通过b6来修改b5,即引用同一空间,同b1,b2的关系
b6.m_iNum = 200;
cout<<"b5: "<<b5.m_iNum<<endl; //result:200
cout<<"b6: "<<b6.m_iNum<<endl; //result:200
cout << endl;
// force to convert 对于内置数据类型,表现未定义行为
const int x = 50;
int* y = (int *)(&x);// same address, but thecontent is different
*y = 200;
cout << "x: "<<x<<"address: "<<&x<<endl; //result: x: 50 address: 002CF880
//为什么呈现出同一个地址存放不同数据?
//常量折叠(由于const,编译器把所有x替换为50,提高运行速度,这是欺骗编译器的行为)
//常量一般分为两种:可折叠常量和不可折叠常量,见文章《const,可折叠常量和不可折叠常量》
cout << "*y: "<<*y<<"address: "<<y<<endl; //result: *y: 200 address: 002CF880
cout<<endl;
// int
const int xx = 50;
int* yy = const_cast<int *> (&xx);// sameaddress, but the content is different
*yy = 200;
cout << "xx: "<<xx<<"address: "<<&xx<<endl; //result: xx: 50 address: 002CF884 //常量折叠,同上
cout << "*yy:"<<*yy<<" address: "<<yy<<endl; //result: *yy: 200 address: 002CF884
cout<<endl;
// int
const int xxx = 50;
int yyy = const_cast<int&> (xxx);// another int //注意:得到another int (原因是:int&是引用的意思,不是取地址,而左面int y是定义int型)
yyy = 200;
cout << "xxx:"<<xxx<<" address: "<<&xxx<<endl; //result: xxx: 50 address: 002CF88C
cout << "yyy:"<<yyy<<" address: "<<&yyy<<endl; //result: yyy: 200 address: 002CF888
}
int _tmain(int argc, char*argv[])
{
foo();
return 0;
}