C++类型转换在实际编程中会经常使用,其实,本质上对象的类型用来解释(interpret)对象。因为,每个对象都占据一块内存空间,这块内存空间存放了一段二进制数据。通过标记该对象的类型,告诉如何看待这块二进制数据。而对象数据类型转换,就是将源类型解释的内存空间转换为目标类型来解释这块内存空间。

  • 传统转换方式(Traditional Type-Casting)是沿用c的方式,通过强制类型转换,隐式转换,显示转换等方式来标识内存空间的解释模式,这种方式功能强大,约束少,但存在安全隐患。因此,通过 static_cast, dynamic_cast, reinterpret_cast,以一种更安全的方式来完成传统转换方式的替换。
  • static_cast 是在编译时就对类型进行检查和转换,是对传统转换的一种规范的表现形式。它会编译期检查源类型与目标类型的关系,以确定这种转换可否实现。
  • dynamic_cast是在运行时动态对源类型和目标类型进行检查,以确定转换可否实现,并且还会进行源类型对象和目标类型对象的完整性检查。
  • reintepret_cast是一种"野蛮"的强行转换,它不过多进行源对象类型和目标对象类型的检查,只将源对象内存空间按照目标对象类型进行解释即可。

一般在转换过程中可以通过如下几种方式来实现:

转换类型 应用场景和使用
 传统的转换方式(C式或函数式)

使用在基本数据类型和自定义对象类型转换,各种类型的强制转换等场合,使用范围很广,缺点是存在安全隐患,因此提供其他四种类型转换在特定的场合来做替代。

这也是延续C的形式,当然这类转换也是可以用static_cast来替换,但是因为是基本类型,所以  传统转换已经很直观

static_cast转换运算符

用在特定场景 对象转换 之上,static_cast会调用相应的构造函数或者重载的转换运算符[不包括赋值运算符]。对于单参构造函数的存在可能会引发一些隐式的转换,因此用static_cast也可以明确的指出类型的转换过程,避免生成多余的临时对象造成效率下降(Google C++ Style Guide)

[虽然static_cast也可以用在有继承关系的类型指针之间,但是还是将这方面的转换交给dynamic_cast来操作吧]

dynamic_cast转换运算符

将其用在具有继承关系的指针类型之间的转换

无论是从基类到子类的转换,还是子类到基类的转换,都将dynamic_cast套上去,也算是标识它们是一家子

reinterpret_cast转换运算符

一般用在将对象指针类型转换到整数类型或者void * (空指针)。

需要注意的是,若要使用其结果,一定要将类型转换回去后使用,否则会存在隐患。也不要将随意的整数转换成指针类型

const_cast转换运算符

用在需要去除掉const限定的时候。

其实这种情况出现的很少,可能的方法在const_cast一文中已经又举例,不过还是反复强调, 使用const_cast转换后,绝对不可试图修改结果的值

  如果任何一种基于指针或引用的转换,套上四个转换运算符之后都失败,那么所要进行的转换可能就触到了"雷区"了:进行了没意义的转换。比如,对于没有关系的两个类型的指针进行了转换,比如试图转换指向方法的指针了。所以转换运算符对于避免代码出错也很有帮助。

下面我们一一分析上述转换类型


一、传统的转换方式(Traditional Type-Casting)

  C++作为C语言的超集,完全继承了C语言所具有的类型转换方法和能力,因此对于这部分在基础数值类型上的转换是比较容易理解的。但是因为C++是面向对象的语言,有类的概念,因此让又多一层需要理解的内容。

  • 1. 隐式转换 (Implicit Conversion)

       隐式转换不需要任何转换运算符,编译器会自动根据类型兼容性进行不同类型之间的转换。

  • 2. 显示转换 (Explicit Conversion)

    显示转换要表明所要转换的目标对象是什么样的类型,然后编译器会做出转换,它有两种格式:

    • C语言格式(C-like Cast)

       (new_type) expression

    • 函数式(Function-style Cast)

        new_type (expression)


二、static_cast <new_type> (expression)

  • 1.  和传统转换类型一样,static_cast可以对基础类型和对象进行类型转换。而基础类型和对象的转换都是其他三个转换运算符所办不到的。

     这些转换跟传统类型转换比较类似,即传统转换均可加上static_cast。

     static_cast会根据下述顺序寻找合适的方法进行类型转换。

    • <1>. 构造函数(Constructor)
    • <2>. 类型转换运算符(Type –Cast Operator)

    *赋值运算符并不被static_cast作为实际的类型转换使用,因为它自身已经是一种运算符,不能再当做转换运算符来用。

  • 2. static_cast不仅可以用在基本数据类型和对象上,还可以用在指针和引用上。

    在指针和引用方面,只有继承关系是可以被static_cast接受的,其他情况的指针和引用转换都会被static_cast直接扔出编译错误,如下代码。

    这就要通过reinterpret_cast<type>()来完成了。

class A{
public:
int m_a;
} int main(){
A* pa = new A();
int ia = static_cast<long>(pa);
return ;
}

  error: invalid static_cast from type ‘A*’ to type ‘long int’
  int ia = static_cast<long>(pa);
                   ^

  继承关系类型间转换可以通过static_cast,但会存在安全隐患,实际上这层关系上的转换又几乎都可以被dynamic_cast所代替。

  因此,static_cast<type>()用在特定场景对象转换之上,static_cast会调用相应的构造函数或者重载的转换运算符[不包括赋值运算符]。对于单参构造函数的存在可能会引发一些隐式的转换,因此用static_cast也可以明确的指出类型的转换过程,避免生成多余的临时对象造成效率下降.[虽然static_cast也可以用在有继承关系的类型指针之间,但是还是将这方面的转换交给dynamic_cast来操作吧]


三、dynamic_cast <new_type> (expression)

  dynamic_cast是动态类型转换,及对象类型的转换过程发生在运行时,如果转换不成功就返回null,转换成功返回目标对象。dynamic在转换的过载中会对源对象和目标对象类型做完整性检查。也就是目标对象的内存模型必须 >= 源目标对象的内存模型

  • 1. 子类 -->基类 ,static_cast和dynamic_cast都是成功并且正确的(所谓成功是说转换没有编译错误或者运行异常;所谓正确是指方法的调用和数据的访问输出是期望的结果),这是面向对象多态性的完美体现。     
  • 2. 基类 -->子类 ,  static_cast和dynamic_cast都是成功的,但是正确性方面,我对两者的结果都先进行了是否非空的判别:
    • dynamic_cast的结果显示是空指针,
    • 而static_cast则是非空指针。

    但很显然,static_cast的结果应该算是错误的,子类指针实际所指的是基类的对象,而基类对象并不具有子类的Study()方法。

  • 3. 对于没有关系的两个类之间的转换,输出结果表明,

    • dynamic_cast依然是返回一个空指针以表示转换是不成立的;
    • static_cast直接在编译期就拒绝了这种转换。
    • reinterpret_cast成功进行了转换,而且返回的值并不是空指针,但是结果显然是错误的。

  最后,程序里还用dynamic_cast希望把用其他转换运算符转换过去的指针转换回来。对于使用static_cast转换后指向了子类对象的基类指针,dynamic_cast判定转换是合理有效的,因此转换成功获得一个非空的指针并且正确输出了结果;而对于reinterpret_cast转换的类型,的确如它的功能一样——重新解析,变成新的类型,所以才得到dynamic_cast判定该类型已经不是原来的类型结果,转换得到了一个空指针。


四、reinterpret_cast <new_type> (expression)

  reinterpret_cast运算符是用来处理无关类型之间的转换;它会产生一个新的值,这个值会有与原始参数(expressoin)有完全相同的内存空间。

  也就是说,reinterpret_cast会将源对象的内存空间按照目标对象的类型格式进行解释,以将源类型对象转换目标类型对象。reinterpret_cast的字面意思:重新解释(类型的内存空间)。转换后的对象是否合法和正确、可用,reinterpret并不做保证。


五、const_cast <new_type> (expression)

  用const_cast来去除const限定,使用const_cast去除const限定的目的绝对不是为了修改它的内容。


六、总结

  以上分别介绍了各种类型转换,及其可能使用的场景。

  总得说来,static_cast和reinterpret_cast运算符要么直接被编译器拒绝进行转换,要么就一定会得到相应的目标类型的值。而dynamic_cast却会进行判别,确定源指针所指的内容,是否真的合适被目标指针接受。如果是否定的,那么dynamic_cast则会返回null。这是通过检查"运行期类型信息"(Runtime type information,RTTI)来判定的,它还受到编译器的影响,有些编译器需要设置开启才能让程序正确运行(导师的PPT详细介绍了Visual Studio的情况),因此dynamic_cast也就不能用传统的转换方式来实现了。

参考 :

  [1]. Type conversions.   http://www.cplusplus.com/doc/tutorial/typecasting/

  [2]. C++标准转换运算符.  http://www.cnblogs.com/ider/archive/2011/07/22/cpp_cast_operator_part2.html

   [3]. C++用户自定义转换(User-Defined Conversion). http://www.cnblogs.com/ider/archive/2011/07/03/cpp_cast_operator_part1.html

[4]. C++标准转换运算符dynamic_cast.  http://www.cnblogs.com/ider/archive/2011/08/01/cpp_cast_operator_part5.html

C++标准转换运算符的更多相关文章

  1. C++标准转换运算符reinterpret_cast

    C++标准转换运算符reinterpret_cast reinterpret_cast <new_type> (expression) reinterpret_cast运算符是用来处理无关 ...

  2. C++标准转换运算符const_cast

    前面讲了C++继承并扩展C语言的传统类型转换方式,最后留下了一些关于指针和引用上的转换问题,没有做详细地讲述.C++相比于C是一门面向对象的语言,面向对象最大的特点之一就是具有“多态性(Polymor ...

  3. C++标准转换运算符 --四种

    具体归纳如下: reinterpret_cast 函数将一个类型的指针转换为另一个类型的指针. 这种转换不用修改指针变量值存放格式(不改变指针变量值),只需在编译时重新解释指针的类型就可做到.rein ...

  4. 【转】C++标准转换运算符reinterpret_cast

    reinterpret_cast<new_type> (expression) reinterpret_cast运算符是用来处理无关类型之间的转换:它会产生一个新的值,这个值会有与原始参数 ...

  5. C++标准转换运算符dynamic_cast

    dynamic_cast <new_type> (expression) dynamic_cast运算符,应该算是四个里面最特殊的一个,因为它涉及到编译器的属性设置,而且牵扯到的面向对象的 ...

  6. 【转】C++标准转换运算符const_cast

    const_cast转换符是用来移除变量的const或volatile限定符. 对于const变量,我们不能修改它的值,这是这个限定符最直接的表现.但是我们就是想违背它的限定希望修改其内容怎么办呢? ...

  7. C++标准转换运算符static_cast

    该运算符把expression转换为type-id类型,但没有运行时类型检查来保证转换的安全性.   中文名 暂无 外文名 static_cast 分    类 强制类型转换 类    型 C++ s ...

  8. 【转】C++标准转换运算符static_cast

    static_cast<new_type> (expression) 虽然const_cast是用来去除变量的const限定,但是static_cast却不是用来去除变量的static引用 ...

  9. const_cast标准转换运算符

    #include <iostream> using namespace std; class A { public: A() { a=; } public: int a; }; void ...

随机推荐

  1. java基础介绍(转)

    很全面的介绍JAVA基础的文档 Java 编程简介,第 1 部分: Java 语言基础 http://www.ibm.com/developerworks/cn/java/j-introtojava1 ...

  2. CSS3特性 盒模型 动画

    转发自0101后花园 CSS3中的动画功能分为Transitions和Animations功能,这两种功能都可以通过改变CSS中的属性值来产生动画效果. 一.Transitions 语法:transi ...

  3. OD调试篇7--笔记及解题报告

    MFC:微软基础类库(英语:Microsoft Foundation Classes,简称MFC)是一个微软公司提供的类库(class libraries),以C++类的形式封装了Windows AP ...

  4. Android RecyclerView单击、长按事件标准实现:基于OnItemTouchListener + GestureDetector

     Android RecyclerView单击.长按事件:基于OnItemTouchListener + GestureDetector标准实现 Android RecyclerView虽然拥有L ...

  5. iOS运行时与method swizzling

    C语言是静态语言,它的工作方式是通过函数调用,这样在编译时我们就已经确定程序如何运行的.而Objective-C是动态语言,它并非通过调用类的方 法来执行功能,而是给对象发送消息,对象在接收到消息之后 ...

  6. WPF的Binding学习笔记(一)

    原文: http://www.cnblogs.com/pasoraku/archive/2012/10/20/2732427.html 一.binding的一般步骤 1,准备数据源     数据源需要 ...

  7. 去除Visual Studio引号中的内容和注释中出现的波浪下划线

    [描述] 使用vs2013,注释或者字符串常量中,经常会出现红色的波浪线,非常烦人. 注意,不是代码错误的那种波浪线,我觉得代码错误智能提示的波浪线还是有必要留着的,这样可以避免过多的编译来发现错误, ...

  8. CentOS 关闭防火墙和selinux

    1)关闭防火墙(每个节点) [Bash shell] 1 2 service iptables stop chkconfig iptables off 2)关闭selinux(重启生效) [Bash ...

  9. Vmware vsphere webservice sdk 连接打开慢的问题

    还在为VimService实例化速度慢的问题烦恼吗?这有一篇文章可以帮你解决问题,英文水平所限,就不翻译了,原文地址http://kb.vmware.com/selfservice/microsite ...

  10. c#检测端口是否被占用

    当我们要创建一个Tcp/Ip Server connection ,我们需要一个范围在1000到65535之间的端口 . 但是本机一个端口只能一个程序监听,所以我们进行本地监听的时候需要检测端口是否被 ...