C++中static_cast/const_cast/dynamic_cast/reinterpret_cast的区别和使用
C风格的强制转换较简单,如将float a转换为int b,则可以这样:b = (int)a,或者b=int(a)。
C++类型转换分为隐式类型转换和显示类型转换。
隐式类型转换又称为标准转换,包括以下几种情况:
(1)、算术转换:在混合类型的算术表达式中,最宽的数据类型成为目标转换类型;
(2)、一种类型表达式赋值给另一种类型的对象:目标类型是被赋值对象的类型;
(3)、将一个表达式作为实参传递给函数调用,此时形参和实参类型不一致:目标转换类型为形参的类型;
(4)、从一个函数返回一个表达式,表达式类型与返回类型不一致:目标转换类型为函数的返回类型。
显示类型转换被称为强制类型转换(cast)。
C++提供了四种强制类型转换形式:static_cast、const_cast、dynamic_cast、reinterpret_cast.每一种适用于特定的场合。
static_cast语法:static_cast<type-id>(expression)
static_cast:仅根据表达式中存在的类型,将expression转换为type-id类型。此运算符可用于将指向基类的指针转换为指向派生类的指针等操作。此类转换并非始终安全。
通常使用 static_cast 转换数值数据类型,例如将枚举型转换为整型或将整型转换为浮点型,而且你能确定参与转换的数据类型。 static_cast转换安全性不如dynamic_cast转换,因static_cast不执行运行时类型检查,而dynamic_cas执行该检查。对不明确的指针的 dynamic_cast将失败,而static_cast的返回结果看似没有问题,这是危险的。尽管 dynamic_cast转换更加安全,但是dynamic_cast只适用于指针或引用,而且运行时类型检查也是一项开销。dynamic_cast 和static_cast运算符可以在整个类层次结构中移动指针。然而,static_cast完全依赖于转换语句提供的信息,因此可能不安全。
static_cast可以反向执行隐式转换,可用于任何隐式允许的转换类型,而在这种情况下结果是不确定的。这需要程序员来验证static_cast转换的结果是否安全。
static_cast可用于将int转换为char。但是,得到的char可能没有足够的位来保存整个int值。同样,这需要程序员来验证static_cast转换的结果是否安全。
static_cast运算符还可用于执行任何隐式转换,包括标准转换和用户定义的转换。
static_cast 运算符可以将整数值显式转换为枚举类型。如果整型值不在枚举值的范围内,生成的枚举值是不确定的。
static_cast运算符将null指针值转换为目标类型的null指针值。
任何表达式都可以通过static_cast运算符显式转换为void类型。目标void类型可以选择性地包含const、volatile或__unaligned特性。
static_cast运算符无法转换掉const、volatile或 __unaligned特性。
只有在确信代码将正常运行的时候,在性能关键代码中使用 static_cast。如果必须在发布模式下使用static_cast,请在调试版本中用 safe_cast(C++ 组件扩展)替换它以确保成功。
任何具有明确定义的类型转换,只要不包含底层const,都可以使用static_cast。
const_cast语法:const_cast<type-id>(expression)
const_cast:从类中移除const、volatile和__unaligned特性。
指向任何对象类型的指针或指向数据成员的指针可显式转换为完全相同的类型(const、volatile 和 __unaligned 限定符除外)。对于指针和引用,结果将引用原始对象。对于指向数据成员的指针,结果将引用与指向数据成员的原始(未强制转换)的指针相同的成员。根据引用对象的类型,通过生成的指针、引用或指向数据成员的指针的写入操作可能产生未定义的行为。
不能使用const_cast运算符直接重写常量变量的常量状态。
const_cast运算符将null指针值转换为目标类型的null指针值。
dynamic_cast语法:dynamic_cast<type-id>(expression)
dynamic_cast:type-id必须是一个指针或引用到以前已定义的类类型的引用或“指向 void的指针”。如果type-id是指针,则expression的类型必须是指针,如果type-id是引用,则为左值。
在托管代码中的 dynamic_cast的行为中有两个重大更改:(1)、为指针的dynamic_cast对指向装箱的枚举的基础类型的指针将在运行时失败,则返回0而不是已转换的指针。(2)、dynamic_cast 将不再引发一个异常,当type-id是指向值类型的内部指针,则转换在运行时失败。该转换将返回0指示运行值而不是引发。
如果type-id是指向expression的明确的可访问的直接或间接基类的指针,则结果是指向type-id类型的唯一子对象的指针。
如果type-id为void*,则做运行时进行检查确定expression的实际类型。结果是指向byexpression的完整的对象的指针。
如果type-id不是 void*,则做运行时进行检查以确定是否由expression指向的对象可以转换为由type-id指向的类型。如果expression类型是type-id类型的基类,则做运行时检查来看是否expression确实指向type-id类型的完整对象。如果为true,则结果是指向type-id类型的完整对象的指针。
dynamic_cast运算符还可以使用执行“相互转换”。使用同一个类层次结构可能进行指针转换。
当使用dynamic_cast时,如果expression无法安全地转换成类型type-id,则运行时检查会引起变换失败。
指针类型的非限定转换的值是null指针。引用类型的非限定转换会引发bad_cast异常。
dynamic_cast支持运行时类型识别。
reinterpret_cast语法:reinterpret_cast<type-id>(expression)
reinterpret_cast:允许将任何指针转换为任何其他指针类型。也允许将任何整数类型转换为任何指针类型以及反向转换。
滥用reinterpret_cast运算符可能很容易带来风险。除非所需转换本身是低级别的,否则应使用其他强制转换运算符之一。
reinterpret_cast运算符可用于char*到int*或One_class*到Unrelated_class*之类的转换,这本身并不安全。
reinterpret_cast的结果不能安全地用于除强制转换回其原始类型以外的任何用途。在最好的情况下,其他用途也是不可移植的。
reinterpret_cast运算符不能丢掉const、volatile或__unaligned特性。
reinterpret_cast运算符将null指针值转换为目标类型的null指针值。
reinterpret_cast的一个实际用途是在哈希函数中,即,通过让两个不同的值几乎不以相同的索引结尾的方式将值映射到索引。
reinterpret_cast通常为运算对象的位模式提供较低层次上的重新解释。reinterpret_cast本质上依赖机器。要想安全地使用reinterpret_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 unnecessary 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.
const_cast can be used to remove or add const to a variable; no other C++ cast is capable of removing it (not even reinterpret_cast). It is important to note that modifying a formerly const value is only undefined if the original variable is const; if you use it to take the const off 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.
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 can use it for more than just casting 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 nullptr in the case of a pointer, or throw std::bad_cast in the case of a reference.
dynamic_cast has some limitations, though. It doesn't work if there are multiple objects of the same type in the inheritance hierarchy (the so-called 'dreaded diamond') and you aren't using virtual inheritance. It also can only go through public inheritance - it will always fail to travel through protected or private inheritance. This is rarely an issue, however, as such forms of inheritance are rare.
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 normally if you cast the result back to the original type, you will get the exact same value (but not if the intermediate type is smaller than the original type).There are a number of conversions that reinterpret_cast cannot do, too. It's used primarily for particularly weird conversions and bit manipulations, like turning a raw data stream into actual data, or storing data in the low bits of an aligned pointer.
C casts are casts using (type)object or type(object). A C-style cast is defined as the first of the following which succeeds:(1)、const_cast; (2)、static_cast(though ignoring access restrictions); (3)、static_cast (see above), then const_cast; (4)、reinterpret_cast; (5)、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 reinterpret_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-style casts also ignore access control when performing a static_cast, which means that they have the ability to perform an operation that no other cast can. This is mostly a kludge, though, and in my mind is just another reason to avoid C-style casts.
测试代码如下:
static_cast.hpp:
#ifndef FBC_MESSY_TEST_STATIC_CAST_HPP_
#define FBC_MESSY_TEST_STATIC_CAST_HPP_#include <iostream>// reference: https://msdn.microsoft.com/zh-cn/library/c36yw7x9.aspx
class B1 {
public:virtual void Test(){}
};class D1 : public B1 {};class CCTest {
public:void setNumber(int);void printNumber() const;
private:int number;
};class B2 { };
class C2 : public B2 { };
class D2 : public C2 { };class A3 { virtual void f(); };
class B3 { virtual void f(); };class B4 { virtual void f(); };
class D4 : public B4 { virtual void f(); };// Returns a hash code based on an address
unsigned short Hash(void *p);void test_static_cast1();
void test_static_cast2(B1* pb, D1* pd);
void test_static_cast3(B1* pb);
void test_static_cast4();
void test_static_cast5();
void test_static_cast6();
void test_static_cast7();
void test_static_cast8();
void test_static_cast9();
void test_static_cast10();#endif // FBC_MESSY_TEST_STATIC_CAST_HPP_
static_cast.cpp:
#include "static_cast.hpp"
#include <iostream>void CCTest::setNumber(int num) { number = num; }void CCTest::printNumber() const {std::cout << "\nBefore: " << number;//this 指针的数据类型为 const CCTest *。//const_cast 运算符会将 this 指针的数据类型更改为 CCTest *,以允许修改成员 number。//强制转换仅对其所在的语句中的其余部分持续const_cast< CCTest * >(this)->number--;std::cout << "\nAfter: " << number;
}void A3::f()
{}void B3::f()
{}void B4::f()
{}void D4::f()
{}unsigned short Hash(void *p) {//reinterpret_cast 允许将指针视为整数类型。结果随后将按位移位并与自身进行“异或”运算以生成唯一的索引(具有唯一性的概率非常高)。//该索引随后被标准 C 样式强制转换截断为函数的返回类型。unsigned int val = reinterpret_cast<unsigned int>(p);return (unsigned short)(val ^ (val >> 16));
}// C风格强制类型转换
void test_static_cast1()
{float a = 1.1, b = 1.9;int ret1 = (int)a;int ret2 = int(b);std::cout << ret1 << " " << ret2 << " " << std::endl;
}void test_static_cast2(B1* pb, D1* pd)
{//与 dynamic_cast 不同,pb 的 static_cast 转换不执行运行时检查。//由 pb 指向的对象可能不是 D 类型的对象,在这种情况下使用 *pd2 会是灾难性的。//例如,调用 D 类(而非 B 类)的成员函数可能会导致访问冲突。D1* pd2 = static_cast<D1*>(pb); // Not safe, D can have fields and methods that are not in B.B1* pb2 = static_cast<B1*>(pd); // Safe conversion, D always contains all of B.
}void test_static_cast3(B1* pb)
{//如果 pb 确实指向 D 类型的对象,则 pd1 和 pd2 将获取相同的值。如果 pb == 0,它们也将获取相同的值。//如果 pb 指向 B 类型的对象,而非指向完整的 D 类,则 dynamic_cast 足以判断返回零。//但是,static_cast 依赖于程序员的断言,即 pb 指向 D 类型的对象,因而只是返回指向那个假定的 D 对象的指针。D1* pd1 = dynamic_cast<D1*>(pb);D1* pd2 = static_cast<D1*>(pb);
}void test_static_cast4()
{char ch;int i = 65;float f = 2.5;double dbl;ch = static_cast<char>(i); // int to chardbl = static_cast<double>(f); // float to doublei = static_cast<int>(ch);
}void test_static_cast5()
{CCTest X;X.setNumber(8);X.printNumber();
}void test_static_cast6(D2* pd)
{//此转换类型称为“向上转换”,因为它将在类层次结构上的指针,从派生的类移到该类派生的类。向上转换是一种隐式转换。C2* pc = dynamic_cast<C2*>(pd); // ok: C is a direct base class pc points to C subobject of pd B2* pb = dynamic_cast<B2*>(pd); // ok: B is an indirect base class pb points to B subobject of pd
}void test_static_cast7()
{A3* pa = new A3;B3* pb = new B3;void* pv = dynamic_cast<void*>(pa);// pv now points to an object of type Apv = dynamic_cast<void*>(pb);// pv now points to an object of type B
}void test_static_cast8()
{B4* pb = new D4; // unclear but okB4* pb2 = new B4;//此转换类型称为“向下转换”,因为它将在类层次结构下的指针,从给定的类移到该类派生的类。D4* pd = dynamic_cast<D4*>(pb); // ok: pb actually points to a DD4* pd2 = dynamic_cast<D4*>(pb2); // pb2 points to a B not a D
}void test_static_cast9()
{A3* pa = new A3;B3* pb = dynamic_cast<B3*>(pa); // fails at runtime, not safe;B not derived from A
}void test_static_cast10()
{int a[20];for (int i = 0; i < 20; i++) {std::cout << Hash(a + i) << std::endl;}
}
主要参考文献:
1. https://msdn.microsoft.com/zh-cn/library/c36yw7x9.aspx
2. http://en.cppreference.com/w/cpp/language/static_cast
3. http://stackoverflow.com/questions/332030/when-should-static-cast-dynamic-cast-const-cast-and-reinterpret-cast-be-used
GitHub:github.com/fengbingchun/Messy_Test
相关文章:

行为型模式:命令模式
LieBrother原文: 行为型模式:命令模式 十一大行为型模式之三:命令模式。 简介 姓名 :命令模式 英文名 :Command Pattern 价值观 :军令如山 个人介绍 : Encapsulate a request as an object,ther…

与旷视、商汤等上百家企业同台竞技?AI Top 30+案例评选等你来秀!
人工智能历经百年发展,如今迎来发展的黄金时期。目前,AI 技术已涵盖自然语言处理、模式识别、图像识别、数据挖掘、机器学习等领域的研究,在汽车、金融、教育、医疗、安防、零售、家居、文娱、工业等行业获得了令人印象深刻的成果。在各行业宣…

在CSS中定义a:link、a:visited、a:hover、a:active顺序
摘自:http://www.qianyunlai.com/post-2.html以前用CSS一直没有遇到过这个问题,在最近给一个本科同学做的项目里面。出现一些问题,搜索引擎查了一些网站和资料,发现很多人问到这个问题,给出的结果我试了试,…
C++中istream的使用
在项目中会经常用到读取一些配置数据,这些数据根据实际需要有可能会调整,如果将这些数据直接嵌入进代码中会非常不便,需要经常调整代码。将这些数据写入配置文件中然后在读入,如果需要调整,只需修改配置文件࿰…

手把手教你用Python模拟登录淘宝
作者 | 猪哥66来源 | 裸睡的猪(ID:IT--Pig)最近想爬取淘宝的一些商品,但是发现如果要使用搜索等一些功能时基本都需要登录,所以就想出一篇模拟登录淘宝的文章!看了下网上有很多关于模拟登录淘宝,但是基本都…

Python之机器学习K-means算法实现
一、前言: 今天在宿舍弄了一个下午的代码,总算还好,把这个东西算是熟悉了,还不算是力竭,只算是知道了怎么回事。今天就给大家分享一下我的代码。代码可以运行,运行的Python环境是Python3.6以上的版本&#…

C++中模板的使用
模板(Template)指C程序设计语言中的函数模板与类模板,是一种参数化类型机制。模板是C泛型编程中不可缺少的一部分。C templates enable you to define a family of functions or classes that can operate on different types of information.模板就是实现代码重用机…
php面试问答
结合实际PHP面试,汇总自己遇到的问题,以及网上其他人遇到的问题,尝试提供简洁准确的答案包含MySQL、Redis、Web、安全、网络协议、PHP、服务器、业务设计、线上故障、个人简历、自我介绍、离职原因、职业规划、准备问题等部分 GitHub: https:…

图解LSTM与GRU单元的各个公式和区别
作者 | Che_Hongshu来源 | AI蜗牛车 (ID: AI_For_Car)因为自己LSTM和GRU学的时间相隔很远,并且当时学的也有点小小的蒙圈,也因为最近一直在用lstm,gru等等,所以今天没事好好缕了一下,接下来跟着我一起区分并…

iphone越狱神器
前阵子刚刚换了iphone5,老婆的4就留给我了。一到手就决定越狱,无意中发现了一款越狱神器:爱思助手http://www.i4.cn/ 确实很好用转载于:https://blog.51cto.com/shanks/1306423
json11库的使用
JSON(JavaScript Object Notation)是一种轻量级的文本数据交换格式,易于让人阅读。同时也易于机器解析和生成。尽管JSON是Javascript的一个子集,但JSON是独立于语言的文本格式,并且采用了类似于C语言家族的一些习惯。JSON解析器和JSON库支持许…
覆盖10亿设备,月活2亿,快应用要取代App?
作者 | 伍杏玲 来源 | CSDN(ID:CSDNnews) 2017 年 1 月 9 日,微信小程序横空出世,紧接着支付宝小程序、百度智能小程序、今日头条小程序、12 大厂商联盟的快应用等布局小程序。自此,小程序迅速改变国内移…

跨域的四种方式
本文主要是关于跨域的几种方式,关于什么是跨域这里就不多说了,写这个也是为了记住一些知识点的。 一. jsonp jsonp的跨域方式很容易理解,页面的的每一个script标签浏览器都会发送get请求获取对应的文本资源,获取到了之后ÿ…

使用模式创建一个面向服务的组件中间件
引言 在本文中,您将了解面向服务的组件中间件在用于资源有限的语音设备时,在设计阶段所应用的模式。它涵盖了项目的问题上下文,并被看成是一组决定因素,是对相关体系结构远景的一个简要概括。您还会得到一份描述,其中介…

OpenCV代码提取:遍历指定目录下指定文件的实现
OpenCV 3.1之前的版本,在contrib目录下有提供遍历文件的函数,用起来比较方便。但是在最新的OpenCV 3.1版本给去除掉了。为了以后使用方便,这里将OpenCV 2.4.9中相关的函数给提取了出来,适合在Windows 64bits上使用。directory.hpp…

姚班三兄弟3万块创业八年,旷视终冲刺港股
作者 | 余洋洋 杨健楷编辑 | 张丽娟来源 | CV智识(ID:CVAI2019)旷视此次 IPO 或将成为整个 AI 行业的信号,不只是“ 四小龙”的另外三家——商汤、依图、云从,整个 AI 行业的创业公司都将受到影响。8月25日晚,AI 独角兽…
Java类加载器详解
Java虚拟机中的类加载有三大步骤:,链接,初始化.其中加载是指查找字节流(也就是由Java编译器生成的class文件)并据此创建类的过程,这中间我们需要借助类加载器来查找字节流. Java虚拟…

linux svn客户端的使用
一下内容转载于:http://blog.chinaunix.net/space.php?uid22976768&doblog&id1640924。这个总结的很好~ windows下的TortoiseSVN是资源管理器的一个插件,以覆盖图标表示文件状态,几乎所以命令都有图形界面支持,比较好用&…

C++中vector的使用
向量std::vector是一种对象实体,能够容纳许多各种类型相同的元素,包括用户自定义的类,因此又被称为序列容器。与string相同,vector同属于STL(Standard Template Library)中的一种自定义的数据类型,可以广义上认为是数组…

说出来你可能不信,现在酒厂都在招算法工程师
导语:虽然夏日已过,但人们喝啤酒的热情还在持续高涨。不过随着大众的追求和理念提升,对于啤酒的要求也越来越高,比如逐渐兴起的精酿之风,都在印证人们在啤酒的口感和风味上,拥有更加「苛刻」的要求。那么这…
「前端面试题系列7」Javascript 中的事件机制(从原生到框架)
前言 这是前端面试题系列的第 7 篇,你可能错过了前面的篇章,可以在这里找到: 理解函数的柯里化ES6 中箭头函数的用法this 的原理以及用法伪类与伪元素的区别及实战如何实现一个圣杯布局?今日头条 面试题和思路解析最近,…

安装Ecshop首页出现报错:Only variables should be passed by referen
出现下面这就话: Strict Standards: Only variables should be passed by reference in D:\wamp\ecshop\includes\cls_template.php on line 406 第406行:$tag_sel array_shift(explode( , $tag)); 解决办法 1 5.3以上版本的问题,应该也和配…

KDD 2019高维稀疏数据上的深度学习Workshop论文汇总
作者 | 深度传送门来源 | 深度传送门【导读】本文是“深度推荐系统”专栏的第九篇文章,这个系列将介绍在深度学习的强力驱动下,给推荐系统工业界所带来的最前沿的变化。本文简要总结一下阿里妈妈在 KDD 2019 上组织的第一届面向高维稀疏数据的深度学习实…
C++中fstream的使用
C中处理文件类似于处理标准输入和标准输出。类ifstream、ofstream和fstream分别从类 istream、ostream和iostream派生而来。作为派生的类,它们继承了插入和提取运算符(以及其他成员函数),还有与文件一起使用的成员和构造函数。可将…

浅谈Disruptor
Disruptor是一个低延迟(low-latency),高吞吐量(high-throughput)的事件发布订阅框架。通过Disruptor,可以在一个JVM中发布事件,和订阅事件。相对于Java中的阻塞队列(ArrayBlockingQueue,LinkedBlockingQueue),Disruptor的优点是性…

web 服务发布注意事项
1、在发布的时候首先查看服务器对外开放的端口,如果没有最好和客户进行沟通需要开放那些对应的端口,要不外界无法访问发布的站点。 2、在oracle需要远程控制服务器的数据库的时候需要开发1521端口。转载于:https://www.cnblogs.com/jzm53550629/p/337563…

OpenCV代码提取:resize函数的实现
之前在http://blog.csdn.net/fengbingchun/article/details/17335477 中有过对cv::resize函数五种插值算法的介绍。这里将OpenCV3.1中五种插值算法的代码进行了提取调整。支持N通道uchar和float类型。经测试,与OpenCV3.1结果完全一致。实现代码resize.hpp࿱…

IBM重磅开源Power芯片指令集?国产芯迎来新机遇?
整理 | 郭芮出品 | CSDN(ID:CSDNnews)自去年 IBM 以 340 亿美元收购了 Linux 巨头红帽之后,这家 107 岁的蓝色巨人终于又在开源方面有大动作了!近日在 Linux 基金会开源峰会上,IBM 宣布向开源社区提供 Powe…

构造函数不能为虚/重载函数总结
构造函数不能为虚/重载函数总结 作为一个类,他最基础的成员函数就要数构造函数了。这里我们先探讨一下构造函数为什么不能是虚函数。 在解决这个问题之前,要先明白类中函数的调用方式。一个类的函数共用一个函数空间,因此在实例化的对象中是不…

通过data:image/png;base64把图片直接写在src里
2019独角兽企业重金招聘Python工程师标准>>> 关于用base64存储图片 网页上有些图片的src或css背景图片的url后面跟了一大串字符,比如:data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAAEAAAAkCAYAAABIdFAMAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZS…