C++中的显示类型转换
本文参考了《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++中的显示类型转换的更多相关文章
- C语言中强制数据类型转换(转)
原文地址不详 字符型变量的值实质上是一个8位的整数值,因此取值范围一般是-128-127,char型变量也可以加修饰符unsigned,则unsigned char 型变量的取值范围是0-255(有些 ...
- 【转载】VC++中的图像类型转换--使用开源CxImage类库
一.CxImage类库简介 这只是翻译了CxImage开源项目主页上的部分简介及简单使用. CxImage类库是一个优秀的图像操作类库.它可以快捷地存取.显示.转换各种图像.有的读者可能说,有那么多优 ...
- C#将image中的显示的图片转换成二进制
原文:C#将image中的显示的图片转换成二进制 1.将Image图像文件存入到数据库中 我们知道数据库里的Image类型的数据是"二进制数据",因此必须将图像文件转换成字节数组才 ...
- Solidity中的基本类型转换
Solidity中的基本类型转换(十四)|入门系列 2017/4/29 posted in Solidity入门系列 点击查看原文,获得优化的排版. 隐式转换 如果一个运算符能支持不同类型.编译器会隐 ...
- 详细理解javascript中的强制类型转换
将值从一种类型转换为另一种类型通常称为类型转换,这是显式的情况:隐式的情况称为强制类型转换,JavaScript 中的强制类型转换总是返回标量基本类型值,如字符串.数字和布尔值. 如何理解: 类型转换 ...
- Struts2中的数据类型转换
Struts2对数据的类型转换 一.Struts2中自带类型转换拦截器 Struts2内部提供了大量转换器,用来完成数据类型转换的问题,有如下 * boolean 和 Boolean * char和 ...
- 关于Java中的基本数据类型转换
Java中的基本类型有四种,其中整型分为byte.short.int.long,浮点型分为float.double,字符型char,布尔型boolean.8种类型的级别由低到高byte->sho ...
- Visual Studio 2010 起始页中 不显示最近使用的项目问题,解决办法
最近新装了vs2010,发现打开vs2010 后 起始页面中的最近使用的栏目中 并未显示最近加载的项目 解决办法如下: 运行 regedit 打开下面的键值: HKEY_CURRENT_USER/So ...
- [转]C++中四种类型转换符的总结
C++中四种类型转换符的总结 一.reinterpret_cast用法:reinpreter_cast<type-id> (expression) reinterpret_cast操 ...
随机推荐
- 金山注入浏览器默认开启上网导航 www.uu114.cn
金山注入浏览器默认开启上网导航 www.uu114.cn 今天突然发现我的电脑所有浏览器打开后,都会默认打开一个www.uu114.cn网站,chrome.firefox和IE都中招了.经过排查,发现 ...
- Mybatis JPA 插件简介
前段时间了解到Spring JPA,感觉挺好用,但其依赖于Hibernate,本人看到Hibernate就头大(不是说Hibernate不好哈,而是进阶太难),于是做了一个迷你版的Mybatis JP ...
- WebDriver--定位元素的8种方式
在UI层面的自动化测试开发中,元素的定位与操作是基础,也是经常遇到的困难所在.webdriver提供了8种定位: 1. id定位:find_element_by_id("id值") ...
- hdu1874畅通工程续(floyd)
畅通工程续 Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submi ...
- TPO-12 C2 A problem of the TA's payroll
TPO-12 C2 A problem of the TA's payroll payroll n. 工资单:在册职工人数:工资名单: paycheck n. 付薪水的支票,薪水 paperwork ...
- 前端开发工程师 - 01.页面制作 - 第3章.HTML
第3章--HTML HTML简介 Hyper Text Markup Language:超文本标记语言--用于标记网页的内容 history: html(1991)雏形 -> html4.01( ...
- 什么是Spark
什么是Spark Apache Spark是一个开源集群运算框架, 相对于Hadoop的MapReduce会在运行完工作后将中介数据存放到磁盘中,Spark使用了存储器内运算技术,能在数据尚未写入硬盘 ...
- 【机器学习】多项式回归sklearn实现
[机器学习]多项式回归原理介绍 [机器学习]多项式回归python实现 [机器学习]多项式回归sklearn实现 使用sklearn框架实现多项式回归.使用框架更方便,可以少写很多代码. 使用一个简单 ...
- LeetCode 94 ——二叉树的中序遍历
1. 题目 2. 解答 2.1. 递归法 定义一个存放树中数据的向量 data,从根节点开始,如果节点不为空,那么 递归得到其左子树的数据向量 temp,将 temp 合并到 data 中去 将当前节 ...
- Java抽象与接口的区别
Java抽象与接口的区别 答案方式一.简单来说,1.接口是公开的,里面不能有私有的方法或变量,是用于让别人使用的,而抽象类是可以有私有方法或私有变量的, 2.另外,实现接口的一定要实现接口里定义的所有 ...