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. Android SQLiteOpenHelper(一)

    SQLiteOpenHelper api解释: A helper class to manage database creation and version management. You creat ...

  2. 安装debian第一天遇到的几个问题及解决方案

    1.当我想要使用sudo时,提示 bash: sudo: command not found 一开始以为是PATH不对,就各种百度各种试 export PATH=${PATH}:$HOME/bin:/ ...

  3. HDU 4822----其实不会这个题

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=4822 并不会做这个题,题解说是LCA(最近公共祖先),并不懂,说一下我自己的思路吧,虽然没能实现出来. 题 ...

  4. 诺基亚XL中Intent.ACTION_VIEW无效的问题

    今天测试播放视频的时候,发现在诺基亚XL机型里不能弹出视频应用列表. 我的代码是: Intent intent = new Intent(Intent.ACTION_VIEW); intent.set ...

  5. bootstrap-12

    按钮(按钮组) 使用方法:按钮组和下拉菜单组件一样,需要依赖于button.js插件才能正常运行.不过我们同样可以直接只调用bootstrap.js文件.使用一个名为btn-group的容器. < ...

  6. c++成员函数的存储方式---11

    原创博客:转载请标明出处:http://www.cnblogs.com/zxouxuewei/ 成员函数属于一个类的成员,出现再类体中.可以被指定为公有,私有或受保护的. 1.在类外面定义成员函数时, ...

  7. VoxelGrid体素滤波器对点云进行下采样

    使用体素化网格方法实现下采样,即减少点的数量,减少点云数据,并同时保持点云的形状特征,在提高配准.曲面重建.形状识别等算法速度中非常实用. PCL实现的VoxelGrid类通过输入的点云数据创建一个三 ...

  8. 龙威零式_团队项目例会记录_18 (Beta架构讨论)

    例会照片 任务更新 姓名 今日完成任务 实际花费时间 明日任务 预计花费时间 谢振威 继续构思beta版本架构并且输出文档 2h #40数据库模块接口定义 2h 杨金键 继续构思beta版本架构并且输 ...

  9. Linux字符界面的优势

    优势一:字符界面占用的系统资源更少,更加适合服务器 优势二:字符界面减少了出错.被攻击的可能性(一.二决定了服务器一般不装图形界面,安全稳定优先)

  10. jquery模板制作左侧导航组件

    /** * Created by bmk on 16-4-25. * * 用法:在自己的js里面把左侧导航的相关图标和对应的列表项名称如下编写: * 版本更新日至按需添加 * 在js中的RNA.run ...