static_cast,dynamic_cast,reinterpret_cast和const_cast的区别详解

C-style cast举例:
 int i;
 double d;
 i = (int) d;

上面的代码就是本来为double类型的d,通过(int)d将其转换成整形值,并将该值赋给整形变量i (注意d本身的值并没有发生改变)。这就是典型的c-style类型转换。

下面是一个简单的程序:


代码如下:

#include <iostream>
using namespace std;

int main(void)
{
         int i;
         double d = 11.29;

i = (int)d;
         cout << i << endl;
         cout << d << endl;

return 0;
}

输出结果:
11
11.29

我们发现d值本身并没有发生任何变化。

在简单的情况下,上面这种类型转换可以很好地工作,但在C++中往往还是不够的,为此ANSI-C++新标准定义的四个转换符,即static_cast、dynamic_cast、reinterpret_cast和const_cast。同时在C++环境中,原先的C-Style的类型转换仍旧可以使用。

1)  static_cast
用法:
static_cast <typeid> (expression)
说明:该运算符把expression转换为typeid类型,但没有运行时类型检查来确保转换的安全性。
用途:
a) 用于类层次结构中基类和派生类之间指针或者引用的转换。up-casting (把派生类的指针或引用转换成基类的指针或者引用表示)是安全的;down-casting(把基类指针或引用转换成子类的指针或者引用)是不安全的。

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

c) 可以把空指针转换成目标类型的空指针(null pointer)。

d) 把任何类型的表达式转换成void类型。
注意: static_cast不能转换掉expression的const、volitale或者__unaligned属性。

2)dynamic_cast
用法:
dynamic_cast <typeid> (expression)
说明:该运算符把expression转换成typeid类型的对象。typeid必须是类的指针、类的引用或者void*。如果typeid是类的指针类型,那么expression也必须是指针,如果typeid是一个引用,那么expression也必须是一个引用。一般情况下,dynamic_cast用于具有多态性的类(即有虚函数的类)的类型转换。

dynamic_cast依赖于RTTI信息,其次,在转换时,dynamic_cast会检查转换的source对象是否真的可以转换成target类型,这种检查不是语法上的,而是真实情况的检查。先看RTTI相关部分,通常,许多编译器都是通过vtable找到对象的RTTI信息的,这也就意味着,如果基类没有虚方法,也就无法判断一个基类指针变量所指对象的真实类型,这时候,dynamic_cast只能用来做安全的转换,例如从派生类指针转换成基类指针。而这种转换其实并不需要dynamic_cast参与。也就是说,dynamic_cast是根据RTTI记载的信息来判断类型转换是否合法的。

用途:主要用于类层次之间的up-casting和down-casting,还可以用于类之间的交叉转换。在进行down-casting时,dynamic_cast具有类型检查的功能,比static_cast更安全。检测在运行时进行。如果被转换的指针不是一个被请求的有效完整的对象指针,返回值为NULL。当用于多态类型时,它允许任意的隐式类型转换以及相反过程。不过,与static_cast不同,在后一种情况里(注:即隐式转 换的相反过程),dynamic_cast会检查操作是否有效。也就是说,它会检查转换是否会返回一个被请求的有效的完整对象。

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

3) reinterpret_cast
用法:reinterpret_cast <typeid>(expression)
说明:转换一个指针为其他类型的指针,也允许将一个指针转换为整数类型,反之亦然。这个操作符能够在非相关的类型之间进行转换。操作结果只是简单的从一个指针到别的指针的值的二进制拷贝,在类型之间指向的内容不做任何类型的检查和转换。这是一个强制转换。使用时有很大的风险,慎用之。
注意:reinterpret _cast不能转换掉expression的const、volitale或者__unaligned属性。

4)const_cast
用法:const_cast<typeid>(expression)
说明:这个类型操纵传递对象的const属性,或者是设置或者是移除。如:
Class C{…}
const C* a = new C;
C* b = const_cast<C*>(a);

如果将上面的const_cast转换成其他任何其他的转换,编译都不能通过,出错的信心大致如下:
“…cannot convert from 'const class C *' to 'class C *'”。

下面的代码是4中casting方法的典型用法示例:


代码如下:

#include <iostream>
     using namespace std;

class Base
     {
     public:
         int _base;
         virtual void printinfo()
         {
              cout << _base << endl;
         }
     };

class Derived : public Base
     {
     public:
         int _derived;
         virtual void printinfo()
         {
              cout << _derived << endl;
         }
     };

int main(void)
     {
         Base b1;
         Derived d1;
         int aInt = 10;
         long aLong = 11;
         float aFloat = 11.11f;
         double aDouble = 12.12;

Derived* pd = static_cast<Derived*>(&b1);                           // down-casting          不安全
         Base* pb = static_cast<Base*>(&d1);                                   // up-casting                安全
         Derived& d = static_cast<Derived&>(b1);                             // down-casting          不安全
         Base& b = static_cast<Base&>(d1);                                      // up-casting                安全

aInt = static_cast<int>(aFloat);                                                // 基本数据类型转换
         void* sth = static_cast<void*>(&aDouble);                            // 将double指针类型转换成void指针类型
         double* bDouble = static_cast<double*>(sth);                    // 将void指针类型转换成double指针类型
         cout << *bDouble << endl;

Base* pb1 = dynamic_cast<Base*>(&d1);
         //Derived* pd1 = dynamic_cast<Derived*>(&b1);                 // 编译时有warning,运行时出错

int bInt = reinterpret_cast<int>(pb1);                                       // 将地址或指针转换成整数
         cout << bInt << endl;
         pb1 = reinterpret_cast<Base*>(bInt);                                     // 将整数转换成地址或指针

int* cInt = reinterpret_cast<int*>(&aFloat);                             // 这个转换的结果会出乎意料
         cout << (int)*cInt << endl;

const Base* bBase = new Base();
         Base* cBase = const_cast<Base*>(bBase);
         //Base* dBase = dynamic_cast<Base*>(bBase);                // 不能通过编译
         //Base* eBase = static_cast<Base*>(bBase);                     // 不能通过编译
         //Base* fBase = reinterpret_cast<Base*>(bBase);             // 不能通过编译

return 0;
}

(0)

相关推荐

  • C++中的类型转换static_cast、dynamic_cast、const_cast和reinterpret_cast总结

    前言 这篇文章总结的是C++中的类型转换,这些小的知识点,有的时候,自己不是很注意,但是在实际开发中确实经常使用的.俗话说的好,不懂自己写的代码的程序员,不是好的程序员:如果一个程序员对于自己写的代码都不懂,只是知道一昧的的去使用,终有一天,你会迷失你自己的. C++中的类型转换分为两种: 1.隐式类型转换: 2.显式类型转换. 而对于隐式变换,就是标准的转换,在很多时候,不经意间就发生了,比如int类型和float类型相加时,int类型就会被隐式的转换位float类型,然后再进行相加运算.而关

  • c++ dynamic_cast与static_cast使用方法示例

    首先dynamic_cast: 复制代码 代码如下: #include <iostream>using namespace std;class A{    public:        virtual ~A(){} //使用dynamic_cast时,必要!};class B:public A{    public:        B(){            m_b=12;        }        void foo(){            cout<<"B

  • 由static_cast和dynamic_cast到C++对象占用内存的全面分析

    static_cast和dynamic_cast是C++的类型转换操作符.编译器隐式执行的任何类型转换都可以由static_cast显式完成,即父类和子类之间也可以利用static_cast进行转换.而dynamic_cast只能用于类之间的转换.那么dynamic_cast的存在还有什么意义呢?因为dynamic_cast提供了一个重要的特性:运行时类型检查来保证转换的安全性. 用static_cast转换存在的危险 我们知道,一个基类指针不需要进行明确的转换操作,就可以指向基类对象或者派生类

  • C++ 中dynamic_cast&lt;&gt;的使用方法小结

    即会作一定的判断.        对指针进行dynamic_cast,失败返回null,成功返回正常cast后的对象指针:        对引用进行dynamic_cast,失败抛出一个异常,成功返回正常cast后的对象引用. 注意:dynamic_cast在将父类cast到子类时,父类必须要有虚函数.例如在下面的代码中将CBasic类中的test函数不定义成        virtual时,编译器会报错:error C2683: dynamic_cast : "CBasic"不是多态

  • static_cast,dynamic_cast,reinterpret_cast,const_cast的区别及用法详解

    1.static_cast对类的指针只能转换有继承关系的类.对普通的指针来说只能在void*和其他指针之间转换.它还可转换简单的类型,比如int到char等.不能提供数字到指针的转换.不能提供不同类型指针之间的转换比如int*到char*. 2.dynamic_cast提供安全的转换如果两个指针不存在继承关系转换会失败返回空指针,如果你提供一个错误的指针那样会发生内存访问异常,因为它会去比较两个类型的虚函数表.虚函数表的指针一般放在对象指针最开始的四字节中,你去访问一个错误的地址这样肯定会发生异

  • static_cast,dynamic_cast,reinterpret_cast和const_cast的区别详解

    C-style cast举例: int i; double d; i = (int) d; 上面的代码就是本来为double类型的d,通过(int)d将其转换成整形值,并将该值赋给整形变量i (注意d本身的值并没有发生改变).这就是典型的c-style类型转换. 下面是一个简单的程序: 复制代码 代码如下: #include <iostream>using namespace std; int main(void){         int i;         double d = 11.2

  • JS处理数据四舍五入(tofixed与round的区别详解)

    1 .tofixed方法 toFixed() 方法可把 Number 四舍五入为指定小数位数的数字.例如将数据Num保留2位小数,则表示为:toFixed(Num):但是其四舍五入的规则与数学中的规则不同,使用的是银行家舍入规则,银行家舍入:所谓银行家舍入法,其实质是一种四舍六入五取偶(又称四舍六入五留双)法.具体规则如下: 简单来说就是:四舍六入五考虑,五后非零就进一,五后为零看奇偶,五前为偶应舍去,五前为奇要进一. 显然这种规则不符合我们平常在数据中处理的方式.为了解决这样的问题,可以自定义

  • AngularJS constant和value区别详解

    angularJS可以通过constant(name,value)和value(name,value)对于创建服务也是很重要的. 相同点是:都可以接受两个参数,name和value. 区别: 1.constant(name,value)可以将一个已经存在的变量值注册为服务,并将其注入到应用的其他部分中.其中,name为注册的常量的名字,value为注册的常量的值或对象. 举例: (1)value为值时: angular.module('myApp') .constant('apiKey','12

  • 基于python中staticmethod和classmethod的区别(详解)

    例子 class A(object): def foo(self,x): print "executing foo(%s,%s)"%(self,x) @classmethod def class_foo(cls,x): print "executing class_foo(%s,%s)"%(cls,x) @staticmethod def static_foo(x): print "executing static_foo(%s)"%x a=A(

  • Oracle10个分区和Mysql分区区别详解

    Oracle10g分区常用的是:range(范围分区).list(列表分区).hash(哈希分区).range-hash(范围-哈希分区).range-list(列表-复合分区). Range分区:Range分区是应用范围比较广的表分区方式,它是以列的值的范围来做为分区的划分条件,将记录存放到列值所在的range分区中. 如按照时间划分,2010年1月的数据放到a分区,2月的数据放到b分区,在创建的时候,需要指定基于的列,以及分区的范围值. 在按时间分区时,如果某些记录暂无法预测范围,可以创建m

  • 基于DOM节点删除之empty和remove的区别(详解)

    要移除页面上节点是开发者常见的操作,jQuery提供了几种不同的方法用来处理这个问题,这里我们开仔细了解下empty和remove方法 empty 顾名思义,清空方法,但是与删除又有点不一样,因为它只移除了 指定元素中的所有子节点. 这个方法不仅移除子元素(和其他后代元素),同样移除元素里的文本.因为,根据说明,元素里任何文本字符串都被看做是该元素的子节点.请看下面的HTML: <div class="hello"><p>这是p标签</p></

  • node.js中grunt和gulp的区别详解

    node.js中grunt和gulp的区别详解 自nodeJS登上前端舞台,自动化构建变得越来越流行.目前最流行的当属grunt和gulp,这两个光看名字挺像,功能也差不多,不过gulp能在grunt这位大哥如日中天的境况下开辟出自己的一片天地,有着她独到的优点. 易用 Gulp相比Grunt更简洁,而且遵循代码优于配置策略,维护Gulp更像是写代码. 高效 Gulp相比Grunt更有设计感,核心设计基于Unix流的概念,通过管道连接,不需要写中间文件. 高质量 Gulp的每个插件只完成一个功能

  • 基于js中this和event 的区别(详解)

    今天在看javascript入门经典-事件一章中看到了 this 和 event 两种传参形式.因为作为一个初级的前端开发人员平时只用过 this传参,so很想弄清楚,this和event的区别是什么,什么情况下用什么比较合适. onclick = changeImg(this)       vs     onclick = changeImg(event) <img src='usa.gif' onclick="changeImg(event)" /> <scrip

  • python dict.get()和dict['key']的区别详解

    先看代码: In [1]: a = {'name': 'wang'} In [2]: a.get('age') In [3]: a['age'] --------------------------------------------------------------------------- KeyError Traceback (most recent call last) <ipython-input-3-a620cb7b172a> in <module>() ----&g

  • java 中同步、异步、阻塞和非阻塞区别详解

    java 中同步.异步.阻塞和非阻塞区别详解 简单点说: 阻塞就是干不完不准回来,一直处于等待中,直到事情处理完成才返回: 非阻塞就是你先干,我先看看有其他事没有,一发现事情被卡住,马上报告领导. 我们拿最常用的send和recv两个函数来说吧... 比如你调用send函数发送一定的Byte,在系统内部send做的工作其实只是把数据传输(Copy)到TCP/IP协议栈的输出缓冲区,它执行成功并不代表数据已经成功的发送出去了,如果TCP/IP协议栈没有足够的可用缓冲区来保存你Copy过来的数据的话

随机推荐