• C++中的static_cast, dynamic_cast和reinterpret_cast


    郑重声明:本文是笔者根据个人理解所写,错误难免,欢迎拍砖!

           可以任意转载、修改,转载时是否标明出处,随君而定!

    static_cast

    用于“良性”和“适度良性”转换,包括不用强制转换(如自动类型转换)。static_cast全部用于明确定义的转换,包括编译器允许我们所做的不用强制转换的“安全”转换和不太安全但清楚定义的转换。

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

    A、典型的非强制变换

    B、窄化(有信息丢失)变换

    C、使用void*的强制变换

    D、隐式类型变换

    E、类层次的静态定位

      a. 向上转换是安全的,即将子类的指针或引用转换为基类
      b. 向下转换是不安全的,即将基类指针或引用转换成子类,因为是静态转换,没有在运行时进行类型检查,应使用dynamic_cast。

     1 int i = 0x7fff;  // max pos value = 32767
     2 long l = 0;
     3 float f = 1.0f;
     4 
     5 // A: typeical castless conversions:
     6 l = static_cast<long>(i);
     7 
     8 // B: narrowing conversions:
     9 i = static_cast<int>(f);
    10 
    11 // C: forcing a conversion from void* :
    12 void* pvoid = &i;
    13 float* pf = static_cast<float*>(pvoid);
    14 
    15 // D: Implicit type conversions, normally performed by the compiler
    16 double d = 0.0;
    17 int x = d; // Automatic type conversion
    18 x = static_cast<int>(d);  // More explicit

     注意:static_cast不能转换掉expression的const、volitale、或者__unaligned属性。

    dynamic_cast

    用法:dynamic_cast < type-id > ( expression )
    该运算符把expression转换成type-id类型的对象。type-id必须是类的指针、类的引用或者void *;
    如果type-id是类指针类型,那么expression也必须是一个指针,如果type-id是一个引用,那么expression也必须是一个引用。

    当使用dynamic_cast来试着向下类型转换一个特定的类型,仅当类型转换是争取的并且是成功的时,返回值是一个指向所需类型的指针,否则它将返回0来表示转换失败。

    dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换
    在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的;

    在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。

     1 #include <iostream>
     2 using namespace std;
     3 
     4 class CPet { public : virtual ~CPet() {} };
     5 class CDog : public CPet {};
     6 class CCat : public CPet {};
     7 
     8 int main()
     9 {
    10     CPet* pPet = new CCat; // Upcast, safe
    11     // Try to cast it to CCat* :
    12     CCat* pCat = dynamic_cast<CCat*>(pPet); // cast success
    13     // Try to cast it to CDog* :
    14     CDog* pDog = dynamic_cast<CDog*>(pPet); // cast fail
    15 
    16     cout << "pDog = " << (long)pDog << endl;
    17     cout << "pCat = " << (long)pCat << endl;
    18 }

     在上面的代码段中,将pPet向下转换为CCat*类型成功了(因为CPet* pPet = new CCat;),转换为CDog*类型失败了,说明dynamic_cast会进行类型检测。

    当使用dynamic_cast时,必须对一个真正多态的层次进行操作(即它含有虚函数),这是因为dynamic_cast使用了存储在VTABLE中的信息来判断实际的类型。

    注意:无论何时进行向下类型转换,我们都应该进行类型检查以确保转换是成功的(即返回值非0)。但我们不用确保指针要完全一样,因为通常在向上和向下类型转换时指针会进行调整(特别是多重继承的情况下)。

    dynamic _cast运行时需要一点额外的开销,不多,但是执行大量的dynamic_cast时就说明我们的设计有问题了,也会导致性能损失。在进行向下转换时,如果我们已经明确知道是什么类型,就可以使用static_cast,以避免调用dynamic_cast产生的额外开销。比如上面的将pPet向下转换为CCat*类型,可以这样写:

    CCat* pCat = static_cast<CCat*>(pPet);

    reinterpret_cast

    这是最不安全的一种转换机制,最有可能出问题。reinterpret_cast把对象假象为模式(为了某种隐秘的目的),仿佛它是一个完全不同的类型对象。这是低级的位模式,C因此而名称不佳。在使用reinterpret_cast做任何事之前,实际上总是需要reinterpret_cast回到原来的类型(或者把变量看做是它原来的类型)。说白了,就是将原来的类型隐藏起来,用的时候再转换回去,否则编译失败。

    用法:reinterpret_casttype-id > (expression)
    type-id必须是一个指针、引用、算术类型、函数指针或者成员指针。
    它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,
    在把该整数转换成原类型的指针,还可以得到原先的指针值)。

    const_cast

    const_cast用来修改类型的const或volatile属性,即可以将const转换为非const以及volatile转换为非volatile,这是const_cast唯一允许的转换。除了const 或volatile修饰之外, type_id和exdivssion的类型是一样的。
    用法:const_cast< type-id > (expression)
    常量指针被转化成非常量指针,并且仍然指向原来的对象;
    常量引用被转换成非常量引用,并且仍然指向原来的对象;常量对象被转换成非常量对象。

    Voiatile和const类试。举如下一例:

     1 class B
     2 {
     3 public:
     4     int m_iNum;
     5 }
     6 void foo()
     7 {
     8     const B b1;
     9     b1.m_iNum = 100; //comile error
    10     B b2 = const_cast<B>((b1);
    11     b2. m_iNum = 200; //fine
    12 }

     上面的代码编译时会报错,因为b1是一个常量对象,不能对它进行改变;

    使用const_cast把它转换成一个常量对象,就可以对它的数据成员任意改变。注意:b1和b2是两个不同的对象。

    简单总结一下:

    dynamic_cast:   通常在基类和派生类之间转换时使用;
    const_cast:   主要针对const和volatile的转换.   
    static_cast:   一般的转换,如果你不知道该用哪个,就用这个。   
    reinterpret_cast:   用于进行没有任何关联之间的转换,比如一个字符指针转换为一个整形数。

    参考资料:

    http://blog.csdn.net/Lambol_8309/article/details/4534338

    http://blog.sina.com.cn/s/blog_4a84e45b0100f57m.html

  • 相关阅读:
    android IntentService生命周期问题
    日志
    python for android : BeautifulSoup 有 bug
    光电耦合器简单介绍以及作用
    cocos2dx 3.1从零学习(五)——动画
    openssl之EVP系列之9---EVP_Digest系列函数的一个样例
    html5 SVG
    CSS选择器
    ISCC2014-reverse
    哇塞!HTML5 实现的雨滴效果 CSS发抖
  • 原文地址:https://www.cnblogs.com/520zijuan/p/2916022.html
Copyright © 2020-2023  润新知