C++中的cast类型转换
1. c强制转换与c++强制转换
c语言强制类型转换主要用于基础的数据类型间的转换,语法为:
(type-id)expression//转换格式1type-id(expression)//转换格式2123
c++除了能使用c语言的强制类型转换外,还新增了四种强制类型转换:static_cast、dynamic_cast、const_cast、reinterpret_cast,主要运用于继承关系类间的强制转化,语法为:
static_cast<new_type> (expression)
dynamic_cast<new_type> (expression)
const_cast<new_type> (expression)
reinterpret_cast<new_type> (expression)1234
备注:new_type为目标数据类型,expression为原始数据类型变量或者表达式。
《Effective C++》中将c语言强制类型转换称为旧式转型,c++强制类型转换称为新式转型。
2. static_cast、dynamic_cast、const_cast、reinterpret_cast
static_cast
static_cast相当于传统的C语言里的强制转换,该运算符把expression转换为new_type类型,用来强迫隐式转换,例如non-const对象转为const对象,编译时检查,用于非多态的转换,可以转换指针及其他,但没有运行时类型检查来保证转换的安全性。它主要有如下几种用法:
①用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。
进行上行转换(把派生类的指针或引用转换成基类表示)是安全的;
进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的。
②用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。
③把空指针转换成目标类型的空指针。
④把任何类型的表达式转换成void类型。
注意:static_cast不能转换掉expression的const、volatile、或者__unaligned属性。
基本类型数据转换举例如下:
char a = 'a';
int b = static_cast<char>(a);//正确,将char型数据转换成int型数据double *c = newdouble;
void *d = static_cast<void*>(c);//正确,将double指针转换成void指针int e = 10;
constint f = static_cast<constint>(e);//正确,将int型数据转换成const int型数据constint g = 20;
int *h = static_cast<int*>(&g);//编译错误,static_cast不能转换掉g的const属性1234567891011
类上行和下行转换:
if(Derived *dp = static_cast<Derived *>(bp)){//下行转换是不安全的//使用dp指向的Derived对象
}
else{//使用bp指向的Base对象
}if(Base*bp = static_cast<Derived *>(dp)){//上行转换是安全的//使用bp指向的Derived对象
}
else{//使用dp指向的Base对象
}12345678910111213
dynamic_cast
dynamic_cast<type*>(e)
dynamic_cast<type&>(e)
dynamic_cast<type&&>(e)123
type必须是一个类类型,在第一种形式中,type必须是一个有效的指针,在第二种形式中,type必须是一个左值,在第三种形式中,type必须是一个右值。在上面所有形式中,e的类型必须符合以下三个条件中的任何一个:e的类型是是目标类型type的公有派生类、e的类型是目标type的共有基类或者e的类型就是目标type的的类型。如果一条dynamic_cast语句的转换目标是指针类型并且失败了,则结果为0。如果转换目标是引用类型并且失败了,则dynamic_cast运算符将抛出一个std::bad_cast异常(该异常定义在typeinfo标准库头文件中)。e也可以是一个空指针,结果是所需类型的空指针。
dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换(cross cast)。
在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的;
在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。dynamic_cast是唯一无法由旧式语法执行的动作,也是唯一可能耗费重大运行成本的转型动作。
(1)指针类型
举例,Base为包含至少一个虚函数的基类,Derived是Base的共有派生类,如果有一个指向Base的指针bp,我们可以在运行时将它转换成指向Derived的指针,代码如下:
if(Derived *dp = dynamic_cast<Derived *>(bp)){//使用dp指向的Derived对象
}
else{//使用bp指向的Base对象
}123456
值得注意的是,在上述代码中,if语句中定义了dp,这样做的好处是可以在一个操作中同时完成类型转换和条件检查两项任务。
(2)引用类型
因为不存在所谓空引用,所以引用类型的dynamic_cast转换与指针类型不同,在引用转换失败时,会抛出std::bad_cast异常,该异常定义在头文件typeinfo中。
void f(const Base &b){try{const Derived &d = dynamic_cast<const Base &>(b); //使用b引用的Derived对象}catch(std::bad_cast){//处理类型转换失败的情况}
}123456789
const_cast
const_cast,用于修改类型的const或volatile属性。
该运算符用来修改类型的const(唯一有此能力的C++-style转型操作符)或volatile属性。除了const 或volatile修饰之外, new_type和expression的类型是一样的。
①常量指针被转化成非常量的指针,并且仍然指向原来的对象;
②常量引用被转换成非常量的引用,并且仍然指向原来的对象;
③const_cast一般用于修改底指针。如const char *p形式。
举例转换如下:
constint g = 20;
int *h = const_cast<int*>(&g);//去掉const常量const属性constint g = 20;
int &h = const_cast<int &>(g);//去掉const引用const属性constchar *g = "hello";
char *h = const_cast<char *>(g);//去掉const指针const属性12345678
reinterpret_cast
new_type必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,再把该整数转换成原类型的指针,还可以得到原先的指针值)。
reinterpret_cast意图执行低级转型,实际动作(及结果)可能取决于编辑器,这也就表示它不可移植。
举一个错误使用reintepret_cast例子,将整数类型转换成函数指针后,vc++在执行过程中会报”…中的 0xxxxxxxxx 处有未经处理的异常: 0xC0000005: Access violation”错误:
#include <iostream>usingnamespacestd;
int output(int p){cout << p <<endl;return0;
}typedefint (*test_func)(int );//定义函数指针test_funcint main(){int p = 10;test_func fun1 = output;fun1(p);//正确test_func fun2 = reinterpret_cast<test_func>(&p);fun2(p);//...处有未经处理的异常: 0xC0000005: Access violationreturn0;
}12345678910111213141516
IBM的C++指南、C++之父Bjarne Stroustrup的FAQ网页和MSDN的Visual C++也都指出:错误的使用reinterpret_cast很容易导致程序的不安全,只有将转换后的类型值转换回到其原始类型,这样才是正确使用reinterpret_cast方式。
MSDN中也提到了,实际中可将reinterpret_cast应用到哈希函数中,如下(64位系统中需将unsigned int修改为unsigned long):
// expre_reinterpret_cast_Operator.cpp// compile with: /EHsc#include <iostream>// Returns a hash code based on an addressunsignedshort Hash( void *p ) {unsignedint val = reinterpret_cast<unsignedint>( p );return ( unsignedshort )( val ^ (val >> 16));
}usingnamespacestd;
int main() {int a[20];for ( int i = 0; i < 20; i++ )cout << Hash( a + i ) << endl;
}12345678910111213141516
另外,static_cast和reinterpret_cast的区别主要在于多重继承,比如
classA {public:int m_a;
};classB {public:int m_b;
};classC : publicA, publicB {};1234567891011
那么对于以下代码:
C c;
printf("%p, %p, %p", &c, reinterpret_cast<B*>(&c), static_cast <B*>(&c));12
前两个的输出值是相同的,最后一个则会在原基础上偏移4个字节,这是因为static_cast计算了父子类指针转换的偏移量,并将之转换到正确的地址(c里面有m_a,m_b,转换为B*指针后指到m_b处),而reinterpret_cast却不会做这一层转换。
因此, 你需要谨慎使用 reinterpret_cast。
3. c++强制转换注意事项
新式转换较旧式转换更受欢迎。原因有二,一是新式转型较易辨别,能简化“找出类型系统在哪个地方被破坏”的过程;二是各转型动作的目标愈窄化,编译器愈能诊断出错误的运用。
尽量少使用转型操作,尤其是dynamic_cast,耗时较高,会导致性能的下降,尽量使用其他方法替代。
C++中的cast类型转换相关推荐
- MYSQL中,CAST函数的使用规则以及convert对比
MYSQL中,CAST函数的使用规则 CAST函数语法规则是:Cast(字段名 as 转换的类型 ),其中类型可以为: CHAR[(N)] 字符型 DATE 日期型 DATETIME 日期和时间型 D ...
- Mysql中的varchar类型转换成int类型
Mysql中的varchar类型转换成int类型 1.实战案例 1.1 student表结构 mysql> desc student; +----------+-------------+--- ...
- C++编程进阶4(C++中的强制类型转换运算符、不要返回自定义类内部成员的指针,引用和迭代器)
十五.C++中的强制类型转换 C语言中的强制类型转换方式有两种 T i = (T)exp; T i = T(exp); 这两种方式没有差别,C++中也支持这两种方式,但是和C++中的强制类型转换运算符 ...
- AS3中的强制类型转换
转自http://www.zhuoqun.net/html/y2007/654.html 每一种编程语言都提供强制类型转换,允许你将某一种数据类型转换成另一种数据类型,AS3自然也不例外.但是虽然我编 ...
- C/C++中的数据类型转换
文章目录 1 隐式类型转换 1.1 隐式类型转换的基本概念 1.2 隐式类型转换的发生点 1.3 浮点数赋值给整形数分析 2 C语言中的强制类型转换 3 C++中的强制类型转换 3.1 static_ ...
- Java学习笔记二十六:Java多态中的引用类型转换
Java多态中的引用类型转换 引用类型转换: 1.向上类型转换(隐式/自动类型转换),是小类型到大类型的转换: 2.向下类型转换(强制类型转换),是大类型到小类型的转换: 3.instanceof运算 ...
- 关于cast类型转换后无法使用索引的优化
关于cast类型转换后无法使用索引的优化 因为表设计时是各开发人员建立的表,同是建立日期字段add_time,有int,还有varchar(50)几种数据类型,如下: (字段有删减) mys ql&g ...
- Java中的基本数据类型转换(自动、强制、提升)
转载自 Java中的基本数据类型转换(自动.强制.提升) 说基本数据类型转换之前,先了解下 Java 中的 8 种基本数据类型,以及它们的占内存的容量大小和表示的范围,如下图所示. 重新温故了下原始数 ...
- (计算机组成原理)第二章数据的表示和运算-第二节7:详解C语言中的强制类型转换
文章目录 (1)无符号数和有符号数 (2)长整数变为短整数 (3)短整数变为长整数 在学习完前面几节的内容后,相信大家对数据是如何在计算机中存储.运算的有了更加深入的认识,那么接下来我们就以更深层次的 ...
最新文章
- html模板(base标签,meta标签,禁用浏览器缓存)+JSP自定义标签荔枝
- 东方卫视收视率查询_肖战被嘲撑不起跨年收视率,看了东方卫视收视曲线,这锅不背!...
- docker使用网桥网络
- 随想录(插件的重要思想)
- 人人商城小程序不能显示批发商品修复方法
- ReviewBoard 系列图文教程之(一)—— 安装
- Android可折叠收缩伸展的Expandable分组RecyclerView:模型抽象和封装(二)
- lenovo服务器换系统重装系统_联想电脑重装系统详细步骤?
- android移动端设计规范,干货|超全面的移动端UI 设计规范整理汇总(下)
- Rundll32.exe使用方法大全
- python中使用ffmpeg合并音频与视频_FFMpeg无损合并视频的多种方法
- 我们管理20人团队的方法
- 一梦三四年——国产MOBA网游的巅峰
- JavaScript 变量命名规范总结
- NLP之语义自动匹配emoji
- java实现极简单的 TXT小说阅读器(第三版)
- 调用移动端“搜索”按键,触发后收起软键盘
- 驱动层SSDT 隐藏进程
- 看片显示服务器不稳定,无限“看片”,资源随便下,这回爽了!
- 老李分享:什么是好战略