现在的位置: 首页 > 综合 > 正文

C++类型转换运算符: static_cast<>,reinterpret_cast<>,dynamic_cast<>, const_cast<>

2019年03月25日 ⁄ 综合 ⁄ 共 6039字 ⁄ 字号 评论关闭

static_cast


用法:static_cast < type-id > ( expression )

该运算符把expression转换为type-id类型,但没有运行时类型检查来保证转换的安全性。它主要有如下几种用法:

用于类层次结构中基类和子类之间指针或引用的转换。

  进行上行转换(把子类的指针或引用转换成基类表示)是安全的;

  进行下行转换(把基类指针或引用转换成子类表示)时,由于没有动态类型检查,所以是不安全的。

用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。

把空指针转换成目标类型的空指针。

把任何类型的表达式转换成void类型。

  注意:static_cast不能转换掉expressionconstvolitale、或者__unaligned属性。

C++static_castreinterpret_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_castC++里的强制类型转换符。

  操作符修改了操作数类型,但仅仅是重新解释了给出的对象的比特模型而没有进行二进制转换。

  例如: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
转换到双精度整数 9static_cast需要正确地为双精度整数
d
补足比特位。其结果为 9.0。而reinterpret_cast的行为却不同:

int n=9;

double d=reinterpret_cast<double & > (n);

  这次,结果有所不同.在进行计算以后, d
包含无用值.
这是因为 reinterpret_cast仅仅是复制 n的比特位到 d,
没有进行必要的分析.

  因此,你需要谨慎使用 reinterpret_cast.

 

注意:static_cast不能转换掉expressionconstvolitale、或者__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;

}

抱歉!评论已关闭.