C++中四种强制类型转换区别详解
C++即支持C风格的类型转换,又有自己风格的类型转换。C风格的转换格式很简单,但是有不少缺点的:
1.转换太过随意,可以在任意类型之间转换。你可以把一个指向const对象的指针转换成指向非const对象的指针,把一个指向基类对象的指针转换成一个派生类对象的指针,这些转换之间的差距是非常巨大的,但是传统的C语言风格的类型转换没有区分这些。
2.C风格的转换没有统一的关键字和标示符。对于大型系统,做代码排查时容易遗漏和忽略。
C++风格完美的解决了上面两个问题。1.对类型转换做了细分,提供了四种不同类型转换,以支持不同需求的转换;2.类型转换有了统一的标示符,利于代码排查和检视。下面分别来介绍这四种转换:static_cast、dynamic_cast、const_cast和reinterpre_cast.
一、static_cast转换
1.基本用法:static_cast<type-id> expression
2.使用场景:
a、用于类层次结构中基类和派生类之间指针或引用的转换
上行转换(派生类---->基类)是安全的;
下行转换(基类---->派生类)由于没有动态类型检查,所以是不安全的。
b、用于基本数据类型之间的转换,如把int转换为char,这种带来安全性问题由程序员来保证
c、把空指针转换成目标类型的空指针
d、把任何类型的表达式转为void类型
3.使用特点
a、主要执行非多态的转换操作,用于代替C中通常的转换操作
b、隐式转换都建议使用static_cast进行标明和替换
二、dynamic_cast转换
1.基本用法:dynamic_cast<type-id> expression
2.使用场景:只有在派生类之间转换时才使用dynamic_cast,type-id必须是类指针,类引用或者void*。
3.使用特点:
a、基类必须要有虚函数,因为dynamic_cast是运行时类型检查,需要运行时类型信息,而这个信息是存储在类的虚函数表中,只有一个类定义了虚函数,才会有虚函数表(如果一个类没有虚函数,那么一般意义上,这个类的设计者也不想它成为一个基类)。
b、对于下行转换,dynamic_cast是安全的(当类型不一致时,转换过来的是空指针),而static_cast是不安全的(当类型不一致时,转换过来的是错误意义的指针,可能造成踩内存,非法访问等各种问题)
c、dynamic_cast还可以进行交叉转换
三、const_cast转换
1.基本用法:const_cast<type-id>expression
2.使用场景:
a、常量指针转换为非常量指针,并且仍然指向原来的对象
b、常量引用被转换为非常量引用,并且仍然指向原来的对象
3.使用特点:
a、cosnt_cast是四种类型转换符中唯一可以对常量进行操作的转换符
b、去除常量性是一个危险的动作,尽量避免使用。一个特定的场景是:类通过const提供重载时,一般都是非常量函数调用const_cast<const T>将参数转换为常量,然后调用常量函数,然后得到结果再调用const_cast <T>去除常量性。
四、reinterpret_cast转换
1.基本用法:reinterpret_cast<type-id>expression
2.使用场景:不到万不得已,不用使用这个转换符,高危操作
3.使用特点:
a、reinterpret_cast是从底层对数据进行重新解释,依赖具体的平台,可移植性差
b、reinterpret_cast可以将整型转换为指针,也可以把指针转换为数组
c、reinterpret_cast可以在指针和引用里进行肆无忌惮的转换
五、各种转换之间的比较
1.static_cast和dynamic_cast
class Base
{
public:
Base(int c = ):_c(c){}
public:
int _c;
};
class Derived:public Base
{
public:
int _d;
int _e;
};
int main(void)
{
int tempA = ;
int tempB = ;
Base base; /*1.无编译告警,但是危险操作,譬如说调用drvPtrA->_d会造成不可预知的后果*/
Derived *drvPtrA = static_cast<Derived *>(&base); drvPtrA->_d = ;
drvPtrA->_e = ;
/*2.输出:tempA为5,tempB为4,踩内存了(机器信息:32位ubuntu,编译器clang++)*/
cout<<tempA<<endl;
cout<<tempB<<endl; /*3.Base中没有虚函数,无法查看运行时信息,编译不过*/
Derived *drvPtrB = dynamic_cast<Derived *>(base); return ;
}
在基类派生类互相转换时,虽然static_cast是在编译期完成,效率更高,但是不安全,上例中就示范了一个踩内存的例子。相比之下因为dynamic_cast可以查看运行时信息,上例如果Base含有虚函数,那么drvPtrB就是一个空指针(这可比踩内存什么的好多了),不能操作Derived中_d的数据从而保证安全性,所以应该优先使用dynamic_cast。
2.static_cast和reinterpret_cast
class BaseA
{
public:
BaseA(int c = ):_c(c){}
int _c;
};
class BaseB
{
public:
BaseB(int d = ):_d(d){}
int _d;
};
int main(void)
{
BaseA baseA;
/*1.编译不过*/
BaseB *baseB = static_cast<BaseB *>(&baseA);
/*2.无任何编译告警,编译通过,正常运行*/
BaseB *baseC = reinterpret_cast<BaseB *>(&baseA);
cout<<baseC->_d<<endl; return ;
}
static_cast虽然也不是一种绝对安全的转换,但是它在转换时,还是会进行必要的检测(诸如指针越界计算,类型检查)。reinterpret_cast完全是肆无忌惮,直接从二进制开始重新映射解释,是极度不安全的,再次提醒,不到万不得已,不要使用。
C++中四种强制类型转换区别详解的更多相关文章
- C++中的四种强制类型转换符详解
		
阅读目录 C++即支持C风格的类型转换,又有自己风格的类型转换.C风格的转换格式很简单,但是有不少缺点的: 转换太过随意,可以在任意类型之间转换.你可以把一个指向const对象的指针转换成指向非con ...
 - [转载]C++中四种强制类型转换方式
		
C++中四种强制类型转换方式 原文地址:http://www.cnblogs.com/home123/p/6763967.html 类型转换有c风格的,当然还有c++风格的.c风格的转换的格式很简单( ...
 - C++中四种强制类型转换方式
		
类型转换有c风格的,当然还有c++风格的.c风格的转换的格式很简单(TYPE)EXPRESSION,但是c风格的类型转换有不少的缺点,有的时候用c风格的转换是不合适的,因为它可以在任意类型之间转换,比 ...
 - 【C++】 四种强制类型转换(static_cast 与 dynamic_cast 的区别!)
		
强制类型转换 1. static_cast 2. dynamic_cast 3. const_cast 4. reinterpret_cast 5. 为什么要需要四种类型转换? 1. static_c ...
 - C++中的关键字用法--- 四种强制类型转换的总结
		
四种强制类型转换的总结(const_cast.static_cast.dynamic_cast.reinterpreter_cast 1. C风格的强制类型转换(Type Cast)很简单,不管什么类 ...
 - 四种强制类型转换的总结(const_cast、static_cast、dynamic_cast、reinterpreter_cast)
		
四种强制类型转换的总结(const_cast.static_cast.dynamic_cast.reinterpreter_cast) 转载 2011年10月03日 23:59:05 标签: stru ...
 - JAVA中的四种JSON解析方式详解
		
JAVA中的四种JSON解析方式详解 我们在日常开发中少不了和JSON数据打交道,那么我们来看看JAVA中常用的JSON解析方式. 1.JSON官方 脱离框架使用 2.GSON 3.FastJSON ...
 - DOS批处理中%cd%与%~dp0的区别详解
		
转载:https://www.jb51.net/article/105325.htm DOS批处理中%cd%与%~dp0的区别详解 Windows下批处理中%cd%和%~dp0都能用来表示当前 ...
 - 基于python中staticmethod和classmethod的区别(详解)
		
例子 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 class A(object): def foo(self,x): print "executing foo ...
 
随机推荐
- 【模板】【学习笔记】noip数学
			
一.素数 欧拉筛 void prime(){ check[]=; ;i<=n;i++){ if(!check[i])prim[++cnt]=i;//这个if语句后面没有大括号!! ;j<= ...
 - QT:QString、QByteArray和char *的转换 【转载】
			
原文网址:http://blog.csdn.net/light1028/article/details/7899541 第一种,数据流的方式,这里只说从QByteArray转向QString. QBy ...
 - BZOJ2054:疯狂的馒头
			
浅谈并查集:https://www.cnblogs.com/AKMer/p/10360090.html 题目传送门:https://lydsy.com/JudgeOnline/problem.php? ...
 - (转)配置ORACLE 11g绿色版客户端和PLSQL环境
			
本文转载自:http://my.oschina.net/jang/blog/83009 本方法是通过使用ORACLE官方提供的精简版客户端,即绿色免安装的客户端. 下载地址(此处提供的是官方各版本下载 ...
 - 框架Mockito
			
一.什么是mock测试,什么是mock对象? 先来看看下面这个示例: 从上图可以看出如果我们要对A进行测试,那么就要先把整个依赖树构建出来,也就是BCDE的实例. 一种替代方案就是使用mocks 从图 ...
 - CTF中常见文件的文件头(十六进制)
			
jpg/jpeg FF D8 FF E0 或 FF D8 FF E1 或 FF D8 FF E8 png 89 50 4E 47 bmp 42 4D 36 5D gif 47 49 46 38 zip ...
 - 初识python notes
			
python数据类型 数字 字符串 列表 元祖 字典 1.为什么要编程 编程的目的是解放人力,这就需要人通过编写程序的方式计算机代替人去自动干活 2.什么是编程语言 编程语言就是人与计算机之间沟通的介 ...
 - Android Tombstone 分析
			
1.什么是tombstone 当一个动态库(native 程序)开始执行时,系统会注册一些连接到 debuggerd 的 signal handlers,当系统 crash 的时候,会保存一个 tom ...
 - Android Fragment用法详解(1)--静态使用Fragment
			
先说明一下,本例子是运行在Android Studio下面的.同样的代码复制粘贴到Eclipse运行却会报错.具体原因我也没有细查.知道的哥们,留言通知下呗. Fragment,也就是碎片,本意是为了 ...
 - 安卓SQLite数据库操作(上)
			
安卓系统自带数据库,名为SQLite.这篇文章我们用一个Demo来讲解安卓操作数据库的例子. By the way, 安卓创建的数据库文件存放在/data/data/<包名>/databa ...