本文参考了《C++ Primer(中文 第5版)》、《王道程序员求职宝典》以及网上相关博客,结合自己的理解写成。个人水平有限,若有错误欢迎指出。

C++中显示转换也成为强制类型转换(cast),有四种:static_cast、dynamic_cast、const_cast、reinterpret_cast。命名的强制类型转换符号一般形式如下:

 cast_name<type>(expression);

以下分别介绍

一、static_cast

任何具有明确定义的类型转换,只要不包含底层const都可以使用static_cast。好吧这句话我不是很懂,换句话:编译器隐式执行的任何类型转换都可以由static_cast显示完成。也就是说,两类型之间可以发生隐式的转换,就可以用static_cast显示转换,有点意思。但要知道的是C++基本类型的指针之间不含有隐式转换(void*除外、const的有些也是可以的),需要显示转换。什么意思?如下:

 double d=3.14;
int i=d; //编译器的隐式转换,等价于下面这条语句
int i=static_cast<int>(d); /*指针之间的转换*/
char str[]="good";
char *ptr=str;
int *p=static_cast<int *>(ptr); //编译错误,两者之间的转换要显式,如下 int *p=(int *)(ptr);

仅当类型之间可隐式转换时(除类层次见的下行转换以外),static_cast的转换才是合法的,否则将出错。(基类指针或引用转换成子类指针或引用为下行转换)

类层次间的下行转换不能通过隐式转换完成,但是可以通过static_cast完成,但是由于没有动态类型检查,所以是不安全的。(至于这个不安全,我们会在dynamic_cast中具体说)。

 class Base{};
class child:public Base{}; Base b;
child c;
c=static_cast<child *>(b); //下行转换,正确;
c=b; //编译错误

二、const_cast

只用使用const_cast才能将const性质转换掉。在这种情况下,试图使用其他三种形式的强制转换都会导致编译时的错误。类似地,除了添加或者删除const特性,用const_cast符来执行其他任何类型转换,都会引起编译错误。

 const double val=3.14;
double *ptr=NULL; /*为了使ptr指向val,使用const_cast*/
ptr=const_cast<double *>(&val);

 三、reinterpret_cast

从语法上看,这个操作符仅用于指针类型的转换(返回值是指针)。它用来将一个类型指针转换为另一个类型指针,它只需在编译时重新解释指针的类型。这个操作符基本不考虑转换类型之间是否是相关的。(参见:红心地瓜的博客野男孩的博客)。

 int *ip=NULL;
char *pc=reinterpret_cast<char *>(ip); /*注:必须牢记pc所指的真实对象是一个int而非字符,如果把pc当成普通的字符指针使用
*就可能在运行时发生错误*/

在《C++ Primer(中文 第五版 )》指出reinterpret_cast很危险,不建议使用。

四、dynamic_cast

该运算符把expression转换成type类型的对象。type必须是类型的指针、类的引用或者void*。type和expression的形式要对应,什么意思了?如:type是指针类型,那么expression也必须是一个指针。

与其他强制类型转换不同,dynamic_cast设计运行时类型检查。dynamic_cast运行时类型检查需要运行时类型信息,而这个信息存储在类的虚函数表中,只有定义了虚函数的类才有虚函数表,故对没有不函数表的类使用会导致dynamic_cast编译错误。

另外,若绑定到引用或指针的对象类型不是目标类型,则dynamic_cast会失败(这点下面细说)。若转换到指针的失败,dynamic_cast的结果是0值,若转换到引用类型的失败,则抛出一个bad_cast类型的异常。

dynamic_cast主要符主要用于类层次间的上行转换和下行转换。

1、在类层次间上行转换时,dynamic_cast和static_cast的效果一样。因为在公有继承方式(保护继承、私有继承,不能隐式转换)下,派生类的对象/对象指针/对象引用可以赋值给基类的对象/对象指针/对象引用(发生隐式转换),反过来则不行。

2、若发生下行转换是安全的,也就是,如果基类指针或者引用的确指向一个派生类对象,这个运算符会传回转型过的指针,若不安全,则会传回空指针。

针对下行转换,换句话说:向下转换的成功与否还与将要转换的类型有关,即要转换的指针指向的对象的实际类型与转换以后的对象类型一定要相同,否则转换失败。

 class Base
{
public:
Base():b() {}
virtual void foo() {}
int b;
}; class Derived:public Base
{
public:
Derived():d() {}
int d;
}; void func(Base *p)
{
Derived *pd1=static_cast<Derived *>(p); //语句1
cout<<pd1->b<<endl;
cout<<pd1->d<<endl;
Derived *pd2=dynamic_cast<Derived *>(p); //语句2
cout<<pd2->b<<endl;
cout<<pd2->d<<endl;
}

1)若调用函数func的实参p指向一个Derived类型的对象,即

 Base *p=new Derived;
func(p);

则pd1和pd2是一样的,并且对这两个指针执行 Derived类的任何操作都是安全的,语句1和2都是输出1、2;

2)若p指向的是一个Base类型的对象,即

 Base *p=new Base;
func(p);

那么pd1指向Base对象的地址,对它进行Derived类型的操作将是不安全的(如访问d),输出d的值时,将会是一个垃圾值;而pd2将是一个空指针,对空指针进行操作,将会发生异常。

Ref:

http://www.cnblogs.com/carsonzhu/p/5251012.html

C++中的显示类型转换的更多相关文章

  1. C语言中强制数据类型转换(转)

    原文地址不详 字符型变量的值实质上是一个8位的整数值,因此取值范围一般是-128-127,char型变量也可以加修饰符unsigned,则unsigned char 型变量的取值范围是0-255(有些 ...

  2. 【转载】VC++中的图像类型转换--使用开源CxImage类库

    一.CxImage类库简介 这只是翻译了CxImage开源项目主页上的部分简介及简单使用. CxImage类库是一个优秀的图像操作类库.它可以快捷地存取.显示.转换各种图像.有的读者可能说,有那么多优 ...

  3. C#将image中的显示的图片转换成二进制

    原文:C#将image中的显示的图片转换成二进制 1.将Image图像文件存入到数据库中 我们知道数据库里的Image类型的数据是"二进制数据",因此必须将图像文件转换成字节数组才 ...

  4. Solidity中的基本类型转换

    Solidity中的基本类型转换(十四)|入门系列 2017/4/29 posted in Solidity入门系列 点击查看原文,获得优化的排版. 隐式转换 如果一个运算符能支持不同类型.编译器会隐 ...

  5. 详细理解javascript中的强制类型转换

    将值从一种类型转换为另一种类型通常称为类型转换,这是显式的情况:隐式的情况称为强制类型转换,JavaScript 中的强制类型转换总是返回标量基本类型值,如字符串.数字和布尔值. 如何理解: 类型转换 ...

  6. Struts2中的数据类型转换

    Struts2对数据的类型转换 一.Struts2中自带类型转换拦截器 Struts2内部提供了大量转换器,用来完成数据类型转换的问题,有如下 * boolean 和 Boolean * char和 ...

  7. 关于Java中的基本数据类型转换

    Java中的基本类型有四种,其中整型分为byte.short.int.long,浮点型分为float.double,字符型char,布尔型boolean.8种类型的级别由低到高byte->sho ...

  8. Visual Studio 2010 起始页中 不显示最近使用的项目问题,解决办法

    最近新装了vs2010,发现打开vs2010 后 起始页面中的最近使用的栏目中 并未显示最近加载的项目 解决办法如下: 运行 regedit 打开下面的键值: HKEY_CURRENT_USER/So ...

  9. [转]C++中四种类型转换符的总结

    C++中四种类型转换符的总结 一.reinterpret_cast用法:reinpreter_cast<type-id> (expression)    reinterpret_cast操 ...

随机推荐

  1. android分析windowManager、window、viewGroup之间关系(一)

    本文将主要介绍addview方法,在windowManager.window.viewGroup中的实现原理.首先将介绍这些类结构关系,然后分析其内在联系,介绍实现原理,最后介绍重要的一个参数wind ...

  2. CentOS 7.2静默安装Oracle11g

      Preface       Today I'm gonna export some test data to another server.The source server is Windows ...

  3. 「日常训练」Queue(Codeforces Round 303 Div.2 D)

    简单到让人不敢相信是D题,但是还是疏忽了一点. 题意与分析 (Codeforces 545D) 题意:n人排队,当一个人排队的时间超过他需要服务的时间就会厌烦,现在要求一个最优排列使得厌烦的人最少. ...

  4. Iview 表单提交: Cannot read property 'validate' of undefined

    提交表单时,提示报这个错,找了半天,然后也百度了很久,一直没找到答案,代码如下: <link href="~/lib/iview3.1.4/styles/iview.css" ...

  5. python里pickle模块

    Pickle模块用于将复杂的文件转化为二进制的文件 pickle模块一般是在源代码里面含有较大的字典或者列表等复杂文件时,我们如果将文件直接写在源代码里面,这样会使得代码很冗余,并且源代码文件所占空间 ...

  6. Eclipse上安装Activiti插件

    今天我们来讲下如何在Eclipse上安装Activiti插件,以后我们要用这个插件来画流程设计图: 这个插件名字是:Activiti BPMN 2.0 designer 具体使用,可以参考官方用户指南 ...

  7. [Install] TeamViewer

    安装TeamViwer 1. $ sudo apt-get -f install 2. 使用gdebi安装TeamViwer. 所以先安装gdebi package. $ sudo apt-get i ...

  8. Machine Learning笔记整理 ------ (二)训练集与测试集的划分

    在实际应用中,一般会选择将数据集划分为训练集(training set).验证集(validation set)和测试集(testing set).其中,训练集用于训练模型,验证集用于调参.算法选择等 ...

  9. 改maven下创建的动态网站依赖的jre版本

    问题描述 通过maven创建一个动态网站后,eclipse会提示一个提醒 Build path specifies execution environment J2SE-1.5. There are ...

  10. 3D动态人脸识别技术分析——世纪晟人脸识别实现三维人脸建模

    - 目录 - 国内3D动态人脸识别现状概况 - 新形势下人脸识别技术发展潜力 - 基于深度学习的3D动态人脸识别技术分析 1. 非线性数据建模方法 2. 基于3D变形模型的人脸建模 - 案例结合——世 ...