php static_castunsigned int,static_cast揭密

本文讨论static_cast<> 和 reinterpret_cast<>。

介绍

大多程序员在学C++前都学过C,并且习惯于C风格(类型)转换。当写C++(程序)时,有时候我们在使用static_cast<>和reinterpret_cast<>时可能会有点模糊。在本文中,我将说明static_cast<>实际上做了什么,并且指出一些将会导致错误的情况。

泛型(Generic Types)

01.

float f = 12.3;

02.

03.

float* pf = &f;

04.

// static cast<>

05.

06.

// 成功编译, n = 12

07.

08.

int n =static_cast(f);

09.

10.

// 错误,指向的类型是无关的(译注:即指针变量pf是float类型,现在要被转换为int类型)

11.

//int* pn = static_cast(pf);

12.

13.

//成功编译

14.

15.

void* pv =static_cast(pf);

16.

17.

//成功编译, 但是 *pn2是无意义的内存(rubbish)

18.

19.

int* pn2 =static_cast(pv);

20.

// reinterpret_cast<>

21.

22.

//错误,编译器知道你应该调用static_cast<>

23.

24.

//int i = reinterpret_cast(f);

25.

26.

//成功编译, 但是 *pn 实际上是无意义的内存,和 *pn2一样

27.

28.

int* pi =reinterpret_cast(pf);

简而言之,static_cast<> 将尝试转换,举例来说,如float-到-integer,而reinterpret_cast<>简单改变编译器的意图重新考虑那个对象作为另一类型。

指针类型(Pointer Types)

指针转换有点复杂,我们将在本文的剩余部分使用下面的类:

01.

class CBaseX

02.

03.

{

04.

05.

public:

06.

07.

int x;

08.

09.

CBaseX() { x = 10; }

10.

11.

void foo() {printf("CBaseX::foo() x=%d\n", x); }

12.

13.

};

14.

class CBaseY

15.

16.

{

17.

18.

public:

19.

20.

int y;

21.

22.

int* py;

23.

24.

CBaseY() { y = 20; py = &y; }

25.

26.

void bar() {printf("CBaseY::bar() y=%d, *py=%d\n", y, *py);

27.

}

28.

29.

};

30.

class CDerived :public CBaseX,public CBaseY

31.

32.

{

33.

34.

public:

35.

36.

int z;

37.

38.

};

情况1:两个无关的类之间的转换

01.

// Convert between CBaseX* and CBaseY*

02.

03.

// CBaseX* 和 CBaseY*之间的转换

04.

05.

CBaseX* pX =new CBaseX();

06.

07.

// Error, types pointed to are unrelated

08.

09.

// 错误, 类型指向是无关的

10.

11.

// CBaseY* pY1 = static_cast(pX);

12.

13.

// Compile OK, but pY2 is not CBaseX

14.

15.

// 成功编译, 但是 pY2 不是CBaseX

16.

17.

CBaseY* pY2 =reinterpret_cast(pX);

18.

19.

// System crash!!

20.

21.

// 系统崩溃!!

22.

23.

// pY2->bar();

正如我们在泛型例子中所认识到的,如果你尝试转换一个对象到另一个无关的类static_cast<>将失败,而reinterpret_cast<>就总是成功“欺骗”编译器:那个对象就是那个无关类。

情况2:转换到相关的类

01.

1. CDerived* pD =new CDerived();

02.

03.

2.printf("CDerived* pD = %x\n", (int)pD);

04.

05.

3.

06.

07.

4.// static_cast<> CDerived* -> CBaseY* -> CDerived*

08.

09.

//成功编译,隐式static_cast<>转换

10.

11.

5. CBaseY* pY1 = pD;

12.

13.

6.printf("CBaseY* pY1 = %x\n", (int)pY1);

14.

15.

// 成功编译, 现在 pD1 = pD

16.

17.

7. CDerived* pD1 =static_cast(pY1);

18.

19.

8.printf("CDerived* pD1 = %x\n", (int)pD1);

20.

21.

9.

22.

23.

10.// reinterpret_cast

24.

25.

// 成功编译, 但是 pY2 不是 CBaseY*

26.

27.

11. CBaseY* pY2 =reinterpret_cast(pD);

28.

29.

12.printf("CBaseY* pY2 = %x\n", (int)pY2);

30.

31.

13.

32.

33.

14.// 无关的 static_cast<>

34.

35.

15. CBaseY* pY3 =new CBaseY();

36.

37.

16.printf("CBaseY* pY3 = %x\n", (int)pY3);

38.

39.

// 成功编译,尽管 pY3 只是一个 "新 CBaseY()"

40.

41.

17. CDerived* pD3 =static_cast(pY3);

42.

43.

18.printf("CDerived* pD3 = %x\n", (int)pD3);

01.

---------------------- 输出 ---------------------------

02.

03.

CDerived* pD = 392fb8

04.

05.

CBaseY* pY1 = 392fbc

06.

07.

CDerived* pD1 = 392fb8

08.

09.

CBaseY* pY2 = 392fb8

10.

11.

CBaseY* pY3 = 390ff0

12.

13.

CDerived* pD3 = 390fec

注意:在将CDerived*用隐式 static_cast<>转换到CBaseY*(第5行)时,结果是(指向)CDerived*(的指针向后) 偏移了4(个字节)(译注:4为int类型在内存中所占字节数)。为了知道static_cast<> 实际如何,我们不得不要来看一下CDerived的内存布局。

CDerived的内存布局(Memory Layout)

0818b9ca8b590ca3270a3433284dd417.png

如图所示,CDerived的内存布局包括两个对象,CBaseX 和 CBaseY,编译器也知道这一点。因此,当你将CDerived* 转换到 CBaseY*时,它给指针添加4个字节,同时当你将CBaseY*转换到CDerived*时,它给指针减去4。然而,甚至它即便不是一个CDerived你也可以这样做。

当然,这个问题只在如果你做了多继承时发生。在你将CDerived转换 到 CBaseX时static_cast<> 和 reinterpret_cast<>是没有区别的。

情况3:void*之间的向前和向后转换

因为任何指针可以被转换到void*,而void*可以被向后转换到任何指针(对于static_cast<> 和 reinterpret_cast<>转换都可以这样做),如果没有小心处理的话错误可能发生。

01.

CDerived* pD =new CDerived();

02.

03.

printf("CDerived* pD = %x\n", (int)pD);

04.

CBaseY* pY = pD;// 成功编译, pY = pD + 4

05.

06.

printf("CBaseY* pY = %x\n", (int)pY);

07.

void* pV1 = pY;//成功编译, pV1 = pY

08.

09.

printf("void* pV1 = %x\n", (int)pV1);

10.

// pD2 = pY, 但是我们预期 pD2 = pY - 4

11.

12.

CDerived* pD2 =static_cast(pV1);

13.

14.

printf("CDerived* pD2 = %x\n", (int)pD2);

15.

16.

// 系统崩溃

17.

18.

// pD2->bar();

01.

---------------------- 输出 ---------------------------

02.

03.

CDerived* pD = 392fb8

04.

05.

CBaseY* pY = 392fbc

06.

07.

void* pV1 = 392fbc

08.

09.

CDerived* pD2 = 392fbc

一旦我们已经转换指针为void*,我们就不能轻易将其转换回原类。在上面的例子中,从一个void* 返回CDerived*的唯一方法是将其转换为CBaseY*然后再转换为CDerived*。

但是如果我们不能确定它是CBaseY* 还是 CDerived*,这时我们不得不用dynamic_cast<> 或typeid[2]。

注释:

1. dynamic_cast<>,从另一方面来说,可以防止一个泛型CBaseY* 被转换到CDerived*。

2. dynamic_cast<>需要类成为多态,即包括“虚”函数,并因此而不能成为void*。

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

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

相关文章

python在国外什么地位-值得收藏!国外最佳Python博客TOP25

python是一个非常容易上手和易用的语言&#xff0c;目前各大互联网公司都能看到Python语言的影子&#xff0c;并且获得众多业界大咖的推荐。 本次我从众多Python的博客中根据谷歌搜索排名和博客在社交论坛的影响力等因素综合考虑&#xff0c;得出最受欢迎的blog。 关于博客&…

Oracle数据库迁移测试数据,Oracle数据库的数据迁移方法

Oracle数据库的数据迁移方法发表于&#xff1a;2008-04-14来源&#xff1a;作者&#xff1a;点击数&#xff1a;随着数据库管理系统和操作系统平台的更新换代的速度的加快&#xff0c;数据库管理员经常需要在两个不同的数据库之间或在两种不同的系统平台之间进行数据迁移。本文…

大顶堆删除最大值_C++|使用STL算法创建、调整、输出最大堆、最小堆

最大堆(又叫大根堆、大顶堆)和最小堆是二叉堆的两种形式&#xff0c;一类很重要的数据结构&#xff0c;如用于堆排序等。最小堆&#xff1a;根结点的键值是所有堆结点键值中最小者&#xff0c;且每个结点的值都比其孩子的值小。最大堆&#xff1a;根结点的键值是所有堆结点键值…

群晖 root_最新群晖DSM7.0降级教程

小广告:隔壁网1212活动开始,群晖DS920+和DS220+满300减40,购买酷狼8T赠送隔壁网邀请码和1年VIP,大刀价格微信咨询momo。 很多童靴,升级到DSM7.0后第三方套件无法用了,比如transmission,玩PT下载的童靴,需要谨慎升级。 这个方法wjq_xp分享的,非常感谢,前面部分和旧的降…

update关联一个视图的时候特别慢_实现一个简单的Vue.js

原文转自 https://const_white.gitee.io/gitee-blog/blog/vue/mini-vue/Vue响应式原理图片引自 孟思行 - 图解 Vue 响应式原理乞丐版 mini-vue实现mini-vue之前&#xff0c;先看看官网的描述。在Vue官网&#xff0c;深入响应式原理中&#xff0c;是这样说明的&#xff1a;每个组…

接口500什么原因_80%小餐饮店几乎都“活“不过500天,为什么?都在这5个原因里...

餐饮创业分享达人 原创作者&#xff1a;秦.关中我是餐饮创业实战经验分享达人&#xff0c;想要了解和学习更多餐饮实战经验&#xff0c;记得关注我哦&#xff01;希望我的分享能帮助大家在创业的道路上少走弯路&#xff0c;不踩坑&#xff0c;为你创业成功助上一臂之力。无论是…

linux 生成hash值命令,linux-从给定哈希计算base64编码哈希?

我创建了一个文件,并在其中输入了一些随机字符串.touch tesseract && echo TestTestTestTestTest > tesseract现在,如果我使用openssl来计算base64哈希[sha256],请运行以下命令&#xff1a;cat tesseract | openssl dgst -sha256 | openssl base64 -A回到我身边KHN0…

padding-left在ie8中不生效_陆国应 律师从民法典第209条来看房屋未过户买卖合同是否生效?...

基本案例(案例来源于大律师教你怎样打官司)&#xff1a;张某与某公司签订了房屋买卖合同。双方在合同中约定&#xff1a;某公司将三居室一套售于张某&#xff0c;价款30万元&#xff0c;并约定该房屋于2018年2月1日前交付使用。此后&#xff0c;张某先后向某公司支付购房款人民…

linux shadow 时间,Linux Shadow-Password-HOWTO - 7. 将 Shadow Suite 放进来使用(1)

这节描述你需要知道有些程式在安装时就已经有 Shadow Suite。大部分的资讯在操作手册可以找到。7.1 新增、修改和删除使用者Shadow Suite 新增下列指令用来新增、修改和删除使用者。 这也是可以安装 adduser 程式。useradduseradd 使令可用在系统中新增使用者。 你也可以采用此…

电脑反应慢卡怎么解决_电脑键盘失灵怎么解决

键盘是电脑中重要的输入设备之一&#xff0c;但在使用的过程中有时可能会碰到键盘失灵的问题&#xff0c;该怎么办呢&#xff1f;别着急&#xff0c;接下来&#xff0c;小编我就来给大家详细的介绍一下电脑键盘出现怎么办&#xff0c;并将解决键盘失灵的操作方法来分享给你们。…

金山手机控usb调试模式开启工具_话筒坏了无法连麦?一招手机秒变电脑麦克风...

前段时间孩子上网课&#xff0c;沉睡多年的摄像头和麦克风被从箱子底请了出来。当连接妥当后&#xff0c;突然发现麦克风失灵了&#xff0c;几经调试宣布报废&#xff01;当时正处于疫情高发期&#xff0c;电脑城肯定是关了&#xff0c;网购是来不及了&#xff0c;怎么办&#…

linux下openldap版本查询,用openldap进行linux认证

用openldap进行linux认证(时间&#xff1a;2010-11-25)(OS:LDAP SERVER:Linux version 2.6.18-8.el5xenLDAP:openldap-devel-2.3.27-5LDAP CLIENT:Linux version 2.6.32-71.el6.i686)一、LDAP Server 安装(一)安装配置#rpm -ihv openldap-servers-2.3.27-5.i386.rpm在安装过程中…

idea的setting界面怎么进_电脑怎么备份系统

电脑怎么备份系统&#xff1f;提前备份系统可以帮助下次系统出现问题后&#xff0c;随时还原备份的系统。下面小白提供两种备份系统的方法。一、系统自带备份一般现在的电脑系统都自带备份还原的功能&#xff0c;不管是win10还是win7都需要手动去备份。优点&#xff1a;可以增加…

快手用旺旺瓶子做机器人_用罐头瓶子做醪糟容易做好保存

醪糟是湖北四川一带的著名风味小吃&#xff0c;醪糟汤圆、醪糟鸡蛋酸甜可口&#xff0c;非常美味。这些年&#xff0c;北方人喜欢它的人也逐渐多了起来&#xff0c;我们单位食堂每周三都做醪糟汤圆大枣汤&#xff0c;是同事们最喜爱、期待的一道美食。我告诉她们可以自己做醪糟…

linux下关闭网络服务,Linux 关闭网络管理服务

关于各种类型数据char、int、double、float 所占空间长度的计算&#xff0c;而char类型让我长姿势了#include int main() { using namespace std; //int A&#xff1d;10; //double B&#xff1d;6; cout << ...python网络编程【一】TCP/IP 是标准的协议,它可以使用世界范…

你不出去卖我拿什么养你_玉树枝干“胳膊粗”,至少养了20年,给钱也不卖!...

玉树是很多花友家里常见的栽培花卉&#xff0c;很多地方叫厚脸皮&#xff0c;是很早进入到国内的多肉植物&#xff0c;经常能够几十年的玉树老桩&#xff0c;长得霸气。玉树叶子四季浓绿油亮&#xff0c;叶子犹如一片片碧玉&#xff0c;枝干古朴苍劲&#xff0c;犹如一棵大树&a…

python面试设计模式问题_聊聊 Python 面试最常被问到的几种设计模式(下)

1. 前言上篇文章 写到了 Python 最常用的 2 种设计模式&#xff0c;单例模式和工厂模式本篇文章我们继续聊聊面试中&#xff0c;Python 面试经常被问到的设计模式&#xff0c;即&#xff1a;构建者模式代理模式观察者模式2. 构建者模式构建者模式&#xff0c;是将一个复杂对象的…

vscode安装swift插件_使用 Webpack 优化 VS Code 插件加载性能

Webpack 这一 JS 模块打包神器相信大家都不陌生了。由于 VS Code 插件大部分也都是 JS/TS 代码 依赖库的形式&#xff0c;因此也可以使用 Webpack 打包&#xff0c;优化性能。经过实测&#xff0c;经过 Webpack 打包优化后的插件&#xff0c;其加载耗时可缩短几倍甚至数十倍之…

全国战争linux添加eth0,linux服务器双线路接入配置

linux服务器双线路接入配置现在有两个专线外接进来分别是移动IP&#xff1a;218。204。242。XXX和电信IP&#xff1a;124。172。245。XXX服务器的地址eth0和eth1的地址分别是&#xff1a;移动IP&#xff1a;218。204。242。XXX和电信IP&#xff1a;124。172。245。XXXDEVICEeth…

c++rpg黑框游戏_NO总本色出演断智大师兄,电竞魔音主C人《超级猎杀》一战成名...

谁说没有智力不能玩RPG&#xff1f;近日&#xff0c;一款名为《超级猎杀》的生存RPG地图在诸多暴雪主播的相继挑战下进入了玩家们的眼帘&#xff0c;要说其中哪位的操作堪称"迷幻"之最&#xff0c;或许No总排第二没人敢称第一。这位菜的同时又自诩无敌的"断智法…