当前位置: 首页 > 编程日记 > 正文

When should static_cast, dynamic_cast and reinterpret_cast be used?

这是我偶然在 http://stackoverflow.com/questions/ 网页上发现的一个问题(类似博客园的博问),问题主要是关于询问应该怎样使用,以及何时使用C++里面的这几种类型转换操作符:static_case, dynamic_cast,以及 reinterpret_cast 。我想这是一个非常典型的问题,因此我就想把这篇帖子转载到我的博客上,也是我第一篇转载的文章。

这个问题的原文链接是:

http://stackoverflow.com/questions/332030/when-should-staticcast-dynamiccast-and-reinterpretcast-be-used

下面是该贴的内容以及最佳答案,我将答案从英文译为中文。原文如下:

When should static_cast, dynamic_cast and reinterpret_cast be used?

=========

Question:

=========

I am reasonably proficient in C++, but I do not have a lot of experience using the cast operators to convert pointers of one type to another. I am familiar with the risks and benefits of pointer casting, as well as the evils of using C-style casts. What I am looking for is a primer on the proper ways to use the various cast operators in C++.

我熟悉C++,但是我对于使用类型转换操作符却没有什么经验。如同使用C风格转换一样,我熟悉使用其风险但也享受着它的好处。我想知道正确使用这些C++转换操作符的基本方法。

What are the proper uses of static_cast, dynamic_cast and reinterpret_cast, and how does one decide which one to use in a specific case?

怎样恰当使用 static_cast, dynamic_cast, reinterpret_cast,怎样在实际使用中决定到底采用它们中的哪一个呢?


            3,107●4●23 asked Dec 1 at 20:11 eJames


            I'm torn between the top two answers. Thank you all for answering. I have chosen coppro's answer because of the detail he goes into regarding static_cast, and because he gives some indication of which should be used in preference to others. – eJames Dec 1 at 20:55

==========

Anwser:

==========

static_cast

static_cast is the first cast you should attempt to use. It does things like implicit conversions between types (such as int to float, or pointer to void*), and it can also call explicit conversion functions (or implicit ones). In many cases, explicitly stating static_cast isn't necessary, but it's important to note that the T(something) syntax is equivalent to (T)something and should be avoided (more on that later). A T(something, something_else) is safe, however, and guaranteed to call the constructor.

static_cast can also cast through inheritance hierarchies. It is unecessary when casting upwards (towards a base class), but when casting downwards it can be used as long as it doesn't cast through virtual inheritance. It does not do checking, however, and it is undefined behavior to static_cast down a hierarchy to a type that isn't actually the type of the object.

static_cast 是你应该首先尝试的转换。它用于隐式类型转换(例如从 int 到 float,或者从指针到 void*),也可以用于显示(或隐式)转换函数。在很多情况下,显示的书写 static_cast 并不必要,但是必须注意的是,T(something)的写法和(T)something的写法是等效的,并且应该避免后面这种写法。 T(something, something_else)是安全的,并且会保证调用构造函数。

static_cast 也可以用于在类的继承方向上进行转换。向上转换(向父类)是不必要的,当向下转换时可以用于转换到 非 virtual的继承(派生)。static_cast不会做对此转换做检查,但是注意如果试图向并非其子类的对象进行转换,则属于未定义行为。

const_cast

const_cast can be used to remove or add const to a variable; no other C++ cast is capable of this (not even reinterpret_cast). It is important to note that using it is only undefined if the orginial variable is const; if you use it to take the const of a reference to something that wasn't declared with const, it is safe. This can be useful when overloading member functions based on const, for instance. It can also be used to add const to an object, such as to call a member function overload.

const_cast also works similarly on volatile, though that's less common.

const_cast 用于去除或者添加变量中的const修饰。其他的C++转换则做不了这件事(即使 reinterpret_cast 也不行)。注意只有原始变量是常量时,该转换才是未定义的。如果你把一个const引用转换到不带const修饰,则是安全的。这在重载一些基于const定义的成员函数非常有用。也可以用于给一个对象添加const,例如调用一个重载成员函数时。

const_cast 也可以用在转换 volatile 变量上,尽管很少见。

dynamic_cast


dynamic_cast is almost exclusively used for handling polymorphism. You can cast a pointer or reference to any polymorphic type to any other class type (a polymorphic type has at least one virtual function, declared or inherited). You don't have to use it to cast downwards, you can cast sideways or even up another chain. The dynamic_cast will seek out the desired object and return it if possible. If it can't, it will return NULL in the case of a pointer, or throw std::bad_cast in the case of a reference.

dynamic_cast 几乎是多态机制所专用的操作符。你可以把任何 多态类型(至少含有一个虚函数,不管是自身的还是继承而来的) 的指针或引用转换到任意的其他对象类型。dynamic_cast 不仅可以向下转换,还可以横向甚至转向其他分支, 它会尽可能选取出你想要的对象并提供。如果它无法转换,则返回NULL(对指针)或者抛出 std::bad_cast (对引用)。

reinterpret_cast


reinterpret_cast is the most dangerous cast, and should be used very sparingly. It turns one type directly into another - such as casting the value from one pointer to another, or storing a pointer in an int, or all sorts of other nasty things. Largely, the only guarantee you get with reinterpret_cast is that if you cast the result back to the original type, you will get the same value. Other than that, you're on your own. reinterpret_cast cannot do all sorts of conversions; in fact it is relatively limited. It should almost never be used (even interfacing with C code using void* can be done with static_cast).

reinterpret_cast 是最危险的一种转换,应保守使用。它把一种类型直接转换到另外一个类型,例如把值从一个指针变为另一个,或者把指针存储成 int,以及所有其他事物。使用reinterpret_cast 我们唯一可以得到的保证是,把转换结果再转回原始类型时,它的值将保持不变。此外,则取决与你自己。reinterpret_cast 不能完成所有种类的转换。实际上它相对而言很受限, 我们应该尽可能不使用它(即使和C代码做接口,我们通过static_cast 可以使用 void*)。

C casts

A C cast ((type)object or type(object)) is defined as the first of the following which succeeds:

const_cast 
static_cast 
static_cast, then const_cast 
reinterpret_cast 
reinterpret_cast, then const_cast 
It can therefore be used as a replacement for other casts in some instances, but can be extremely dangerous because of the ability to devolve into a static_cast, and the latter should be preferred when explicit casting is needed, unless you are sure static_cast will succeed or reinterpret_cast will fail. Even then, consider the longer, more explicit option.

C类型转换 ( (type)object 或 type(object) ) 定义为以下任何一个,假如它能够成功:

const_cast 
static_cast 
static_cast, then const_cast 
reinterpret_cast 
reinterpret_cast, then const_cast 

所以我们可以在某些场合使用C类型转换来代替那些显示的操作符,但是必须强调的是,它有可能成为 static_cast (而static_cast 应该用于必须进行显示转换的场合) ,这是极端危险的,除非你确信 static_cast 会成功而 reinterpret_cast 会失败。即便如此,为长远考虑,应该明确制定具体的转换操作符。

I hope this helps!

希望这些对你有帮助!


link|flag answered Dec 1 at 20:26 coppro 3,107●4●23

----------------------------------------------------------------------
 
  I hope others up-vote this answer - it's the only one that actually describes static_cast in enough detail, specifically the limitations on casting within an inheritance hierarchy. – Earwicker Dec 1 at 20:32 
 nice answer mate – litb Dec 1 at 20:35 
 Agreed with Earwicker, and +1 from here – jalf Dec 1 at 20:39 

Can you clean up the const_cast section? It is worded confusingly. The last sentence is repeated. Any cast can add const, only const_cast can remove it. The middle section should read more like: "It is undefined behavior to modify a variable defined as const, only possible through use of const_cast" – Greg Rogers Dec 1 at 21:01

你可以整理下 const_cast 哪一段吗? 描述的比较混乱。最后一句是重复的。任何转换都可以添加const,但是只有 const_cast 可以去掉const。中间一段似乎更应该理解为:“修改一个声明为const的变量属于未定义行为,只有通过 const_cast 才可以办到”。- Greg Rogers


 I would recommend as first option dynamic_cast<> which, of course only works as described above. Whenever you can do dynamic_cast<> it will check that the type is really what you believe. – dribeas Dec 1 at 21:02


===============================================================
static_cast

It is able to do the reverse of what an implicit conversion can do. Meaning: narrow (long -> int), widen (int -> long), base-to-derived, void*-to-T* for example. You can't use it for the stuff that an reversed implicit conversion cannot do. (I.e you cannot cast an int* into int).

用于和隐式转换可用时的反向转换。意味着:向窄(long->int),向宽(int->long),父类到子类,void*到T* 等等。不能用于隐式转换无法完成的反向转换。(例如把int*转换为int)。

dynamic_cast

It is used to cast a base pointer into a derived pointer. If the base pointer doesn't point to an object of the type of the derived, it returns 0. 
It is used to cast a base reference into a derived reference. If the reference isn't pointing to an object of the derived, it throws std::bad_cast. 
It can be considered the checked cast equivalent to static_cast, in that it checks whether the object pointed to really is of the derived type.

用于把父类指针转换为子类指针,如果实际指向不是子类对象,返回0。
用于把父类引用转换为子类引用,如果实际引用不是子类对象,抛出std::bad_cast。
当检验对象是否确实指向子类类型时,可以认为该检验等效于static_cast。

reinterpret_cast

It is used to cast a pointer type to a wide enough integral type and back to the original pointer type. 
It is used to cast between pointer types of incompatible types (int* to double* for example). The result of that mapping is unspecified, but it's possible to do so.

用于把指针类型转换到整形以及转回到指针类型。
用于在不相容的两种对象的指针类型之间进行转换(例如int*到double*)。结果将是无法预料的,但有时可能会这样做。

const_cast

It is used to cast away const or volatile. It is used in the rare cases when you have a originally non-const object, which is pointed to by a pointer-to-const or referenced to by a reference-to-const. Casting away constness is considered evil and should not be done if it can be avoided.

用于去掉 const 或 volatile 的转换。它仅仅在很少的情况下使用,即当你拥有const指针指向或const引用引用的一个非const对象时。去掉const的转换是很“邪恶”的,能不用则不用。


C-style cast is equivalent to the following C++ style casts. The first cast that succeeds is taken (See 5.4 in the Standard):

C转换和下面首先成功的C++类型转换等效(参见标准的5.4):

const_cast, static_cast, static_cast followed by const_cast, reinterpret_cast, reinterpret_cast followed by const_cast.

link|flag edited Dec 1 at 20:31 answered Dec 1 at 20:24 litb 31.9k●1●41●129 
===================================================================================================================
 
  Beautiful answer, litb. It is a close call between yours and coppro's. Thank you! – eJames Dec 1 at 20:52 
 thanks eJames. i forgot to mention some important things though, which coppro thought about. so you did actually the right choice i think. have fun :) – litb Dec 2 at 0:00


===================================================================================================================

Use dynamic_cast for converting pointers/references within an inheritance hierarchy.

Use static_cast for ordinary type conversions.

Use reinterpret_cast for low-level reinterpreting of bit patterns. Use with extreme caution.

Use const_cast for casting away const/volatile. Avoid this unless you are stuck using a const-incorrect API.

answered Dec 1 at 20:22 Fred Larson 1,783●2●12

使用 dynamic_cast 在一个类继承等级内进行转换。
使用 static_cast 做常规类型转换。
使用 reinterpret_cast 在底层bit模式下做转换。使用时尤其需要小心。
使用 const_cast 去掉const/volatile。除非你需要使用无法接受const的API否则避免使用。

-- Fred Larson

相关文章:

Java项目:养老院管理系统(java+SSM+JSP+Easyui+maven+mysql)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 运行环境&#xff1a; JDK1.8、tomcat8、eclipse、mysql5.6、Navicat 功能实现&#xff1a; 用户: 用户名,登录密码,姓名,性别,出生日期,用户照片,联系电话,邮箱,家庭地址,注册时间 老人: 老人编号,姓名,…

Linux访问Windows磁盘实现共享

业务需求说明&#xff1a;公司在部署hadoop集群和DB server与SAN存储&#xff0c;公司的想法是前端通过DB Server能够将非结构化的数据能放进SAN存储当中&#xff0c;而hadoop集群也能够访问这个SAN存储。因此需要在SAN磁盘阵列中开辟一个共享区域&#xff0c;这个区域技能让DB…

ubuntu环境ceph配置入门(一)

为什么80%的码农都做不了架构师&#xff1f;>>> 环境&#xff1a;ubuntu server 14.04 64bit&#xff0c;安装ceph版本0.79 正常情况下应有多个主机&#xff0c;这里为了快速入门以一台主机为例&#xff0c;多台主机配置方式类似。 1. 配置静态IP及主机名 静态IP配…

mysql查看当前实时连接数

静态查看: SHOW PROCESSLIST; SHOW FULL PROCESSLIST; SHOW VARIABLES LIKE %max_connections%; SHOW STATUS LIKE %Connection%; 实时查看&#xff1a; mysql> show status like Threads%; -------------------------- | Variable_name | Value | ------------…

lsof 简介

lsof简介 lsof&#xff08;listopen files&#xff09;是一个列出当前系统打开文件的工具。在linux环境下&#xff0c;任何事物都以文件的形式存在&#xff0c;通过文件不仅仅可以访问常规数据&#xff0c;还可以访问网络连接和硬件。所以如传输控制协议 (TCP) 和用户数据报协…

Java项目:健身器材商城系统(java+Jdbc+Servlet+Ajax+Fileupload+mysql)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 一、项目运行 环境配置&#xff1a; Jdk1.8 Tomcat8.5 mysql Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09; 项目技术&#xff1a; Jdbc Servlert html css JavaScrip…

Xcode中如何解决无法使用svn命令行的问题

今天在自己机器上安装了xp虚拟机,然后在xp虚拟机上安装了svn的服务器.发现原本Xcode5以后就自带的svn竟然在终端无法使用命令行,出现了以下的错误: xcrun: error: active developer path ("/Volumes/Xcode/Xcode.app/Contents/Developer") does not exist, use xcode…

查看和设置MySQL数据库字符集(转)

查看和设置MySQL数据库字符集作者&#xff1a;scorpio 2008-01-21 10:05:17 标签&#xff1a; 杂谈 Liunx下修改MySQL字符集&#xff1a;1.查找MySQL的cnf文件的位置find / -iname *.cnf -print /usr/share/mysql/my-innodb-heavy-4G.cnf/usr/share/mysql/my-large.cnf/usr/sha…

数据库管理工具dbeaver

https://dbeaver.io/ 转载于:https://www.cnblogs.com/mingzhang/p/11016229.html

linux文件权限详解

linux文件权限详解 一、文件和目录权限概述在linux中的每一个文件或目录都包含有访问权限&#xff0c;这些访问权限决定了谁能访问和如何访问这些文件和目录。通过设定权限可以从以下三种访问方式限制访问权限&#xff1a;只允许用户自己访问&#xff1b;允许一个预先指定的用户…

linux定时器(crontab)实例

linux实验示例----实现每2分钟将“/etc”下面的文件打包存储到“/usr/lobal”目录下 Step1&#xff1a;编辑当前用户的crontab并保存终端输入&#xff1a;>crontab -u root -l #查看root用户设置的定时器>crontab -u root -e #进入vi编译模式 00-59/2 * * * * /bin/bash …

Java项目:晚会抽奖系统(java+Jdbc+Servlet+Ajax+mysql)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 一、项目运行 环境配置&#xff1a; Jdk1.8 Tomcat8.5 mysql Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09; 项目技术&#xff1a; Jdbc Servlert html css JavaScrip…

hdu 4587 2013南京邀请赛B题/ / 求割点后连通分量数变形。

题意&#xff1a;求一个无向图的&#xff0c;去掉两个不同的点后最多有几个连通分量。 思路&#xff1a;枚举每个点&#xff0c;假设去掉该点&#xff0c;然后对图求割点后连通分量数&#xff0c;更新最大的即可。算法相对简单&#xff0c;但是注意几个细节&#xff1a; 1&…

javascript中 (function(){})();如何理解?

javascript中 (function(){})();如何理解? javascript中: (function(){})()是匿名函数&#xff0c;主要利用函数内的变量作用域&#xff0c;避免产生全局变量&#xff0c;影响整体页面环境&#xff0c;增加代码的兼容性。 (function(){})是一个标准的函数定义&#xff0c;但是…

通过IP地址和子网掩码与运算计算相关地址

知道ip地址和子网掩码后可以算出&#xff1a; 1、网络地址 2、广播地址 3、地址范围 4、本网有几台主机 例1&#xff1a;下面例子IP地址为1921681005子网掩码是2552552550。算出网络地址、广播地址、地址范围、主机数。 一)分步骤计算 1) 将IP地址和子网掩码换算为二进制…

Java项目:兼职平台系统(java+Springboot+ssm+HTML+maven+Ajax+mysql)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 一、项目运行 环境配置&#xff1a; Jdk1.8 Tomcat8.5 mysql Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09; 项目技术&#xff1a; HTML Springboot SpringMVC MyBatis…

java实现时间的比较

时间大小的比较以及把String类型的时间转换为Date类是时间在开发中是非常常见的&#xff0c;下面的主要是一个工具方法 public class Test {public static void main(String[] args) {// TODO Auto-generated method stubString sTime "2015-07-13";String fTime &…

在eclipse中通过基于spring data的easyrest风格的maven项目操纵cassandra和lucene

一、项目前提步骤1>、创建键空间CREATE KEYSPACE mykeyspaceWITH REPLICATION { class : SimpleStrategy, replication_factor : 1 };2>、创建表和关系数据库一样&#xff0c;开发前需要先建表&#xff0c;再操纵CREATE TABLE tweet (id uuid PRIMARY KEY,nickName text…

JAVA 多线程实现包子铺(买包子,吃包子)

1 package baozi;2 3 /*4 生产者&#xff08;包子铺&#xff09;类&#xff1a;是一个 线程类&#xff0c;继承Thread5 设置线程任务&#xff08;run&#xff09;&#xff1a;生产包子6 对包子 进行判断7 true&#xff1a;有包子8 包子铺调用wait方法进…

字符串面试题(一)字符串逆序

字符串逆序可以说是最经常考的题目。这是一道入门级的题目&#xff0c;相信80%的程序员经历过这道题。给定一个字符串s&#xff0c;将s中的字符顺序颠倒过来&#xff0c;比如s"abcd"&#xff0c;逆序后变成s"dcba"。 普通逆序 基本上没有这么考的&#xf…

Java项目:在线淘房系统(租房、购房)(java+SpringBoot+Redis+MySQL+Vue+SpringSecurity+JWT+ElasticSearch+WebSocket)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 该系统有三个角色&#xff0c;分别是&#xff1a;普通用户、房屋中介、管理员。普通用户的功能&#xff1a;浏览房屋信息、预约看房、和中介聊天、申请成为中介等等。房屋中介的功能&#xff1a;发布房屋信息…

Be a person

做人不能太实诚 尤其是干我们这行的 多久时间能做完 你自己心里要有个估算 然后把时间再往后延 别他妈给自己找罪受 转载于:https://www.cnblogs.com/wskgjmhh/p/4644840.html

Solr配置文件分析与验证

前面一篇开始学习solr的时候&#xff0c;做了个入门的示例http://6738767.blog.51cto.com/6728767/1401865。虽然可以检索出内容&#xff0c;但总和想象的结果有差异——比如&#xff0c;检索“天龙”两个字&#xff0c;按常规理解&#xff0c;就应该只出来《天龙八部》才对&am…

oracle启用归档日志

一、开启归档 1、查看归档信息 SQL> archive log list Database log mode No Archive Mode Automatic archival Disabled Archive destination USE_DB_RECOVERY_FILE_DEST Oldest online log sequence 244 Current log sequence …

C++派生类与基类构造函数调用次序

本文用来测试C基类和派生类构造函数&#xff0c;析构函数&#xff0c;和拷贝构造函数的调用次序。运行环境&#xff1a;SUSE Linux Enterprise Server 11 SP2 (x86_64) #include <iostream>using namespace std;class Base{public:Base(){cout << "Base Cons…

Java项目:在线点餐系统(java+Springboot+Maven+mybatis+Vue+mysql+Redis)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 项目描述&#xff1a; 这是一个基于SpringBootVue框架开发的在线点餐系统。首先&#xff0c;这是一个前后端分离的项目。具有一个在线点餐系统该有的所有功能。 项目功能&#xff1a; 此项目分为两个角色&…

js 打开窗口window.open

js改变原有的地址 window.open(webPath/index?codecode,_self); 转载于:https://www.cnblogs.com/hwaggLee/p/4645680.html

中兴SDH原理介绍及中兴E300网管介绍

姓名苟忠兴培训课程中兴SDH原理介绍及中兴E300网管介绍培训心得1、 SDH概念&#xff1a;SDH&#xff08;Synchronous Digital Hierarchy&#xff0c;同步数字体系&#xff09;是一种将复接、线路传输及交换功能融为一体、并由统一网管系统操作的综合信息传送网络。2、 PDH缺点&…

bootstrap 冻结表格,冻结表头

需要的文件下载&#xff1a; bootstrap-table:https://github.com/wenzhixin/bootstrap-table bootstrap-table-fiex-column:https://github.com/wenzhixin/bootstrap-table-fixed-columns 参考来源&#xff1a;https://www.cnblogs.com/Kyaya/p/9004237.html 1.引入文件 2. bo…

Linux多线程与同步

作者&#xff1a;Vamei 出处&#xff1a;http://www.cnblogs.com/vamei 欢迎转载&#xff0c;也请保留这段声明。谢谢&#xff01; 典型的UNIX系统都支持一个进程创建多个线程(thread)。在Linux进程基础中提到&#xff0c;Linux以进程为单位组织操作&#xff0c;Linux中的线程也…