C++ 强制类型转换符(static_cast、reinterpret_cast、const_cast和dynamic_cast)

将类型名作为强制类型转换运算符的做法是C语言的老式做法,C++ 为保持兼容而予以保留。

C++ 引入了四种功能不同的强制类型转换运算符以进行强制类型转换:static_cast、reinterpret_cast、const_cast 和 dynamic_cast。

强制类型转换是有一定风险的,有的转换并不一定安全,如把整型数值转换成指针,把基类指针转换成派生类指针,把一种函数指针转换成另一种函数指针,把常量指针转换成非常量指针等。C++ 引入新的强制类型转换机制,主要是为了克服C语言强制类型转换的以下三个缺点。

1) 没有从形式上体现转换功能和风险的不同。

例如,将 int 强制转换成 double 是没有风险的,而将常量指针转换成非常量指针,将基类指针转换成派生类指针都是高风险的,而且后两者带来的风险不同(即可能引发不同种类的错误),C语言的强制类型转换形式对这些不同并不加以区分。

2) 将多态基类指针转换成派生类指针时不检查安全性,即无法判断转换后的指针是否确实指向一个派生类对象。

3) 难以在程序中寻找到底什么地方进行了强制类型转换。

强制类型转换是引发程序运行时错误的一个原因,因此在程序出错时,可能就会想到是不是有哪些强制类型转换出了问题。

如果采用C语言的老式做法,要在程序中找出所有进行了强制类型转换的地方,显然是很麻烦的,因为这些转换没有统一的格式。

而用 C++ 的方式,则只需要查找_cast字符串就可以了。甚至可以根据错误的类型,有针对性地专门查找某一种强制类型转换。例如,怀疑一个错误可能是由于使用了 reinterpret_cast 导致的,就可以只查找reinterpret_cast字符串。

C++ 强制类型转换运算符的用法如下:

强制类型转换运算符 <要转换到的类型> (待转换的表达式)

例如:

double d = static_cast <double> (3*5);  //将 3*5 的值转换成实数

下面分别介绍四种强制类型转换运算符。

static_cast

static_cast 用于进行比较“自然”和低风险的转换,如整型和浮点型、字符型之间的互相转换。另外,如果对象所属的类重载了强制类型转换运算符 T(如 T 是 int、int* 或其他类型名),则 static_cast 也能用来进行对象到 T 类型的转换。

static_cast 不能用于在不同类型的指针之间互相转换,也不能用于整型和指针之间的互相转换,当然也不能用于不同类型的引用之间的转换。因为这些属于风险比较高的转换。

static_cast 用法示例如下:

    #include <iostream>using namespace std;class A{public:operator int() { return 1; }operator char*() { return NULL; }};int main(){A a;int n;char* p = "New Dragon Inn";n = static_cast <int> (3.14);  // n 的值变为 3n = static_cast <int> (a);  //调用 a.operator int,n 的值变为 1p = static_cast <char*> (a);  //调用 a.operator char*,p 的值变为 NULLn = static_cast <int> (p);  //编译错误,static_cast不能将指针转换成整型p = static_cast <char*> (n);  //编译错误,static_cast 不能将整型转换成指针return 0;}

reinterpret_cast

reinterpret_cast 用于进行各种不同类型的指针之间、不同类型的引用之间以及指针和能容纳指针的整数类型之间的转换。转换时,执行的是逐个比特复制的操作。

这种转换提供了很强的灵活性,但转换的安全性只能由程序员的细心来保证了。例如,程序员执意要把一个 int* 指针、函数指针或其他类型的指针转换成 string* 类型的指针也是可以的,至于以后用转换后的指针调用 string 类的成员函数引发错误,程序员也只能自行承担查找错误的烦琐工作:(C++ 标准不允许将函数指针转换成对象指针,但有些编译器,如 Visual Studio 2010,则支持这种转换)。

reinterpret_cast 用法示例如下:

#include <iostream>
using namespace std;
class A
{
public:int i;int j;A(int n):i(n),j(n) { }
};
int main()
{A a(100);int &r = reinterpret_cast<int&>(a); //强行让 r 引用 ar = 200;  //把 a.i 变成了 200cout << a.i << "," << a.j << endl;  // 输出 200,100int n = 300;A *pa = reinterpret_cast<A*> ( & n); //强行让 pa 指向 npa->i = 400;  // n 变成 400pa->j = 500;  //此条语句不安全,很可能导致程序崩溃cout << n << endl;  // 输出 400long long la = 0x12345678abcdLL;pa = reinterpret_cast<A*>(la); //la太长,只取低32位0x5678abcd拷贝给paunsigned int u = reinterpret_cast<unsigned int>(pa);//pa逐个比特拷贝到ucout << hex << u << endl;  //输出 5678abcdtypedef void (* PF1) (int);typedef int (* PF2) (int,char *);PF1 pf1;  PF2 pf2;pf2 = reinterpret_cast<PF2>(pf1); //两个不同类型的函数指针之间可以互相转换
}

程序的输出结果是:
200, 100
400
5678abed

第 19 行的代码不安全,因为在编译器看来,pa->j 的存放位置就是 n 后面的 4 个字节。 本条语句会向这 4 个字节中写入 500。但这 4 个字节不知道是用来存放什么的,贸然向其中写入可能会导致程序错误甚至崩溃。

上面程序中的各种转换都没有实际意义,只是为了演示 reinteipret_cast 的用法而已。在编写黑客程序、病毒或反病毒程序时,也许会用到这样怪异的转换。

reinterpret_cast体现了 C++ 语言的设计思想:用户可以做任何操作,但要为自己的行为负责。

const_cast

const_cast 运算符仅用于进行去除 const 属性的转换,它也是四个强制类型转换运算符中唯一能够去除 const 属性的运算符。

将 const 引用转换为同类型的非 const 引用,将 const 指针转换为同类型的非 const 指针时可以使用 const_cast 运算符。例如:

const string s = "Inception";
string& p = const_cast <string&> (s);
string* ps = const_cast <string*> (&s); // &s 的类型是 const string*

dynamic_cast

用 reinterpret_cast 可以将多态基类(包含虚函数的基类)的指针强制转换为派生类的指针,但是这种转换不检查安全性,即不检查转换后的指针是否确实指向一个派生类对象。dynamic_cast专门用于将多态基类的指针或引用强制转换为派生类的指针或引用,而且能够检查转换的安全性。对于不安全的指针转换,转换结果返回 NULL 指针。

dynamic_cast 是通过“运行时类型检查”来保证安全性的。dynamic_cast 不能用于将非多态基类的指针或引用强制转换为派生类的指针或引用——这种转换没法保证安全性,只好用 reinterpret_cast 来完成。

dynamic_cast 示例程序如下:

#include <iostream>
#include <string>
using namespace std;
class Base
{  //有虚函数,因此是多态基类
public:virtual ~Base() {}
};
class Derived : public Base { };
int main()
{Base b;Derived d;Derived* pd;pd = reinterpret_cast <Derived*> (&b);if (pd == NULL)//此处pd不会为 NULL。reinterpret_cast不检查安全性,总是进行转换cout << "unsafe reinterpret_cast" << endl; //不会执行pd = dynamic_cast <Derived*> (&b);if (pd == NULL)  //结果会是NULL,因为 &b 不指向派生类对象,此转换不安全cout << "unsafe dynamic_cast1" << endl;  //会执行pd = dynamic_cast <Derived*> (&d);  //安全的转换if (pd == NULL)  //此处 pd 不会为 NULLcout << "unsafe dynamic_cast2" << endl;  //不会执行return 0;
}

程序的输出结果是:
unsafe dynamic_cast1

第 20 行,通过判断 pd 的值是否为 NULL,就能知道第 19 行进行的转换是否是安全的。第 23 行同理。

如果上面的程序中出现了下面的语句:

Derived & r = dynamic_cast <Derived &> (b);

那该如何判断该转换是否安全呢?不存在空引用,因此不能通过返回值来判断转换是否安全。C++ 的解决办法是:dynamic_cast 在进行引用的强制转换时,如果发现转换不安全,就会拋出一个异常,通过处理异常,就能发现不安全的转换。

转自:C++强制类型转换运算符(static_cast、reinterpret_cast、const_cast和dynamic_cast)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/738947.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【rk3229 android7.1.2 替换默认输入法】

问题平台描述 问题描述解决方法 郑重声明:本人原创博文&#xff0c;都是实战&#xff0c;均经过实际项目验证出货的 转载请标明出处:攻城狮2015 Platform: Rockchip CPU:rk3229 OS:Android 7.1.2 Kernel: 3.10 问题描述 国内客户&#xff0c;觉得安卓自带的输入法不好用&#x…

智能警用装备柜管理系统|智能化可视化管理

智能警用装备柜管理系统|智能化可视化管理 我司&#xff08;JIONCH集驰&#xff09;警用装备管理系统&#xff08;智装备DW-S304&#xff09;是依托互云计算、大数据、RFID技术、数据库技术、AI、视频分析技术对警用装备进行统一管理、分析的信息化、智能化、规范化的系统。 智…

返回值不同算方法重载么?为什么?

1、典型回答 返回值不同不算方法重载 方法重载&#xff08;Overloading&#xff09;是指在同一个类中定义了多个同名方法&#xff0c;但它们的参数列表不同&#xff0c;方法重载要求方法&#xff1a; 名称相同参数类型、参数个数或参数顺序&#xff0c;至少有一个不同 方法…

IOS面试题object-c 91-100

91. 简述Object-C中nonatomic与atomic有什么区别?atomic是Objective-C使用的一种线程保护技术,它是为了防止写操作在未完成的时候被另外一个线程读取。从而造成数据错误。这种机制是非常耗费系统资源的,所以在iphone这种小的移动设备上,如果没有使用多线程间的通讯编程。建…

分布式之LoadBalancer

一、LoadBalancer介绍 Spring Cloud LoadBalancer是Spring Cloud官方自己提供的客户端负载均衡器,抽象和实现&#xff0c;用来替代Ribbon&#xff08;已经停更&#xff09;&#xff0c; 二、Ribbon和Loadbalance 对比 组件组件提供的负载策略支持负载的客户端Ribbon随机 Ran…

什么是网站服务器?

今天小编主要来带领大家聊一聊什么是网站服务器吧&#xff01; 网站服务器又被称为Web服务器&#xff0c;是在互联网数据中心中存放网站的服务器&#xff0c;网站服务器存储了网站上的所有内容&#xff0c;具体来说&#xff0c;服务器是一台存储了Web服务器软件以及网站的组成文…

[MYSQL数据库]--约束

前言 作者&#xff1a;小蜗牛向前冲 名言&#xff1a;我可以接受失败&#xff0c;但我不能接受放弃 如果觉的博主的文章还不错的话&#xff0c;还请点赞&#xff0c;收藏&#xff0c;关注&#x1f440;支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 目录 一、空属性…

C++的学习

代码练习 输入一个字符串&#xff0c;统计其中大写字母、小写字母、数字、空格以及其他字符的个数 #include <iostream>using namespace std;int main() {cout << "请输入一个字符串" << endl;string str;getline(cin,str);int capital 0;int l…

HTTP/1.1 协议优化方案探讨

前言 HTTP/1.1 是目前广泛应用的网络协议之一&#xff0c;虽然已经存在多年&#xff0c;但我们仍然可以通过优化来提升其性能和效率。本文将从优化思路的角度出发&#xff0c;探讨如何在 HTTP/1.1 协议下实现优化&#xff0c;包括避免发送重复 HTTP 请求、减少 HTTP 请求次数、…

分享个好用的GPT网站

目录 一、背景 二、功能描述 1、写代码 2、联网查询 3、AI绘图 一、背景 我现在的开发工作都依靠ChatGPT&#xff0c;效率提升了好几倍。这样一来&#xff0c;我有更多时间来摸鱼&#xff0c;真是嘎嘎香~ ⭐⭐⭐点击直达 ⭐⭐⭐ 二、功能描述 1、写代码 import java.ut…

flink:通过table api把文件中读取的数据写入MySQL

当写入数据到外部数据库时&#xff0c;Flink 会使用 DDL 中定义的主键。如果定义了主键&#xff0c;则连接器将以 upsert 模式工作&#xff0c;否则连接器将以 append 模式工作 package cn.edu.tju.demo2;import org.apache.flink.streaming.api.environment.StreamExecutionE…

portainer管理远程docker和docker-swarm集群

使用前请先安装docker和docker-compose&#xff0c;同时完成docker-swarm集群初始化 一、portainer-ce部署 部署portainer-ce实时管理本机docker&#xff0c;使用docker-compose一键拉起 docker-compose.yml version: 3 services:portainer:container_name: portainer#imag…

LeetCode 26. 删除有序数组中的重复项。(通过JavaScript实现)

给你一个 非严格递增排列 的数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff0c;返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。 考虑 nums 的唯一元素的数量为 k &#xff0c;你…

2-Docker-应用-多容器部署Django+Vue项目(nginx+uwsgi+mysql)

摘要&#xff1a; 本文详细介绍了如何使用Docker部署一个多容器DjangoVue项目&#xff0c;包括nginx、uwsgi和mysql。文章内容涵盖了基础知识回顾、需求分析、设计方案、实现步骤、技巧与实践、性能优化与测试、常见问题与解答以及结论与展望。 阅读时长&#xff1a;约60分钟…

要将这个本地HTML文件转换为图片

要将这个本地HTML文件转换为图片&#xff0c;您可以按照以下步骤操作&#xff1a; 1. 打开文件&#xff1a; - 使用您的网页浏览器&#xff08;如Google Chrome、Mozilla Firefox、Microsoft Edge等&#xff09;打开这个本地HTML文件。您可以通过在浏览器地址栏中输入文件的…

制冷系统管道焊接气焊安全操作

气焊操作安全教育&#xff1a; 1、检查气焊用具完好牢固无损&#xff0c;不得贴粘有&#xff08;机油&#xff09;&#xff1b; 2、气瓶余压&#xff08;2KG&#xff09;停止使用&#xff1b;清除动火 10 米范围内易燃易爆物料&#xff1b; 3、库房内动火要 做好通风排气&…

python基础——函数进阶【多个返回值,多种传参方式,匿名函数】

&#x1f4dd;前言&#xff1a; 这篇文章主要记录一下在python中&#xff0c;关于函数的进阶常用知识&#xff0c;建议对编程中的函数有一定了解的读者阅读&#xff0c;如果想了解一下函数的最基础内容&#xff0c;也可先看这篇文章C语言——函数 在本文&#xff0c;我会主要讲…

ETAS入门篇-1、ISOLAR-A软件介绍

目录 ISOLAR-A介绍 体系结构 特性 架构 Explorers和Views 编辑 Editors

ORM(对象关系映射)的概念,并说明在Python中如何使用

ORM&#xff08;对象关系映射&#xff09;的概念&#xff0c;并说明在Python中如何使用 ORM&#xff08;对象关系映射&#xff09;是一种编程技术&#xff0c;它实现了将关系型数据库中的数据映射到程序中的对象模型&#xff0c;使得开发者能够使用面向对象的方式来操作数据…

海格里斯HEGERLS智能托盘四向车系统为物流仓储自动化升级提供新答案

随着实体企业面临需求多样化、订单履行实时化、商业模式加速迭代等挑战&#xff0c;客户对物流仓储解决方案的需求也逐渐趋向于柔性化、智能化。作为近十年来发展起来的新型智能仓储设备&#xff0c;四向车系统正是弥补了先前托盘搬运领域柔性解决方案的空白。随着小车本体设计…