C++中比较全面的四种强制类型转化的比较static_cast const_cast reinterpret_cast dynamic_cast

在C++中有static_cast,dynamic_cast,reinterpret_cast,const_cast四种强制类型转化符,而对于这四种强制类型转化符很多程序员都不能正确的区分它们的用处。而我这篇文章或许为那部分人解惑。

一: static_cast的使用

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

     1. 用于类层次结构中基类和子类之间指针或引用的转换,通常进行上行转换是安全的;而进行下行转换时,由于没有动态类型检查,所以是不安全的。static_cast<Derived *>(base)

     2. 用于内置基本数据类型之间的转换,如将int转换成double,int转换成enum。而这种转化也是不安全的。 static_cast<double>(int)

     3. 将空指针转换成目标类型的空指针。 static_cast<int*>(void*)

     4. 将任何类型的表达式转换成void类型。
注意:static_cast不能转换掉expression的const、volitale、或者__unaligned前缀修饰符


需要注意的是:

static_cast  和reinterpret_cast 在类继承层次间可以完成向下类型强制转化,但是dynamic_cast需要运行时(动态)的完成类型检查


二: dynamic_cast的使用  

     dynamic_cast < type-id > ( expression ) 该运算符将expression转换成type-id类型的对象。type-id必须是类的指针、类的引用或者void *;但记住就是不能为对象本身,要用对象本身可用static_cast<B>(b).

如果type-id是类指针类型,那么expression也必须是一个指针,如果type-id是一个引用,那么expression也必须是一个引用。

记住使用dynamic_cast转化中基类必须至少要有一个虚方法,记住哟

dynamic_cast是类层次间相关的(也即是类之间有继承关系),他会在运行时检查底层对象的运行时信息,对于类指针,如果类型强制转化没有意义,则会返回NULL,而对于

引用则会抛出std::bad_cast异常

比如:


class conV
{
public:
    int n_M;
   virtual void fun()
   {
    cout<<"virtual void fun()"<<endl;
   }
};

class convv
{
public:
    void fun();
    
};

void main()

{   

    conV *v;
    conV rv;
    conV &rf=rv;
    
    try{
    dynamic_cast<convv&>(rf);//这里很特别rf引用必须是多态类型,也就是说conV类中要有virtual方法呵,不信你去掉 virtual void fun()中的virtual
    
    }catch(std::bad_cast)
    {
    cout<<"std::bad_cast"<<endl;
    exit(0);

    }
}


  dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的;在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。
class B{
  public:
  int m_iNum;
  virtual void foo();
};
class D:public B{
  public:
  char *m_szName[100];
};
void func(B *pb){
  D *pd1 = static_cast<D *>(pb);
  D *pd2 = dynamic_cast<D *>(pb);
}
  在上面的代码段中,如果pb指向一个D类型的对象,pd1和pd2是一样的,并且对这两个指针执行D类型的任何操作都是安全的;
  但是,如果pb指向的是一个B类型的对象,那么pd1将是一个指向该对象的指针,对它进行D类型的操作将是不安全的(如访问m_szName),而pd2将是一个空指针。
  另外要注意:B要有虚函数,否则会编译出错;static_cast则没有这个限制。这是由于运行时类型检查需要运行时类型信息,而这个信息存储在类的虚函数表(关于虚函数表的概念,详细可见<Inside c++ object model>)中,只有定义了虚函数的类才有虚函数表,没有定义虚函数的类是没有虚函数表的。
  另外,dynamic_cast还支持交叉转换(cross cast)。如下代码所示。
class A{
  public:
  int m_iNum;
  virtual void f(){}
};
class B:public A{
};
class D:public A{
};
void foo(){
  B *pb = new B;
  pb->m_iNum = 100;
  D *pd1 = static_cast<D *>(pb); //compile error
  D *pd2 = dynamic_cast<D *>(pb); //pd2 is NULL
  delete pb;
}
  在函数foo中,使用static_cast进行转换是不被允许的,将在编译时出错;而使用 dynamic_cast的转换则是允许的,结果是空指针。

三: reinterpret_cast使用  

     reinterpret_cast< type-id > ( expression )是C++里的强制类型转换符。


reinterpret_cast是比static_cast更强大的功能,static_cast不能支持从int和指针的相互转化,也不支持从类层次(继承关系)上不相关的转化,但支持类层次相关的转化。如从一个对象或对象引用转化到另一个对象和对象引用,他们是不相关的。几乎所有的c++无意义的转化static_cast都不支持,但是reinterpret_cast可以,可以完成上面说的那些情况,但是随之带来的是安全性更低。

操作符修改了操作数类型,但仅仅是重新解释了给出的对象的比特模型而没有进行二进制转换。
  例如:int *n= new int ;
           double *d=reinterpret_cast<double*> (n);
  在进行计算以后, d 包含无用值. 这是因为 reinterpret_cast 仅仅是复制 n 的比特位到 d, 没有进行必要的分析。因此, 需要谨慎使用 reinterpret_cast. 并且:reinterpret_cast 只能在指针之间转换。

四: const_cast使用

     const_cast<type_id> (expression) 该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外, type_id和expression的类型是一样的。
  常量指针被转化成非常量指针,并且仍然指向原来的对象;
  常量引用被转换成非常量引用,并且仍然指向原来的对象;常量对象被转换成非常量对象。
  Voiatile和const类试。举如下一例:
class B{
  public:
  int m_iNum;
}
void foo(){
  const B b1;
  b1.m_iNum = 100; //comile error
  B b2 = const_cast<B>(b1);
  b2. m_iNum = 200; //comile ok
}
  上面的代码编译时会报错,因为b1是一个常量对象,不能对它进行改变;
  使用const_cast把它转换成一个非常量对象,就可以对它的数据成员任意改变。注意:b1和b2是两个不同的对象。
C++中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 a example.";
  i = reinterpret_cast<int>(p);
  此时结果,i与p的值是完全相同的。reinterpret_cast的作用是说将指针p的值以二进制(位模式)的方式被解释为整型,并赋给i,一个明显的现象是在转换前后没有数位损失。


类型强制转化总结: 记住有一点就是static_cast必须是类层次相关的,而reinterpret_cast可以也可不是类层次相关


转化情况                                                                                                                                       转化方法
删除常量型                                                                                                                                   const_cast

语言支持的显示类型转化如int和double间转化                                                                      static_cast


一种对象转化到另一种对象,即使类层次间相关 (就是有继承关系)                                                                  无法完成 reinterpret_cast<Object2>(Object1);//报错
   

一种对象转化到另一种对象引用,即使类层次间 相关                                                        可以完成reinterpret_cast<Object2&>(Object1);但是用static_cast <Object2&>         (Object1);必须是类层次相关,否则报错                                              

类层次间相关 一种对象指针 转化到另一种对象指针                                                           reinterpret_cast<Object2*>(Object1); static_cast<Object2*>(Object1); dynamic_cast<Object2*>(Object1)都可

类层次间相关 一种对象引用 转化到另一种对象引用                                                         reinterpret_cast<Object2&>(Object1); static_cast<Object2&>(Object1); dynamic_cast<Object2&>(Object1)三种都可


指针和int型之间的转化, 注意不是和float或double                                                               reinterpret_cast


函数指针的转化                                                                                                                            reinterpret_cast

你可能感兴趣的:(C++中比较全面的四种强制类型转化的比较static_cast const_cast reinterpret_cast dynamic_cast)