C++类型转换运算符

  • 1. dynamic_cast
  • 2. const_cast
  • 3. static_cast
  • 4. reinterpret_cast

摘自以下图书:

  1. 《C++ Primer Plus》Stephen Prata

在 C++的创始人 Bjame Stroustrup 看来,C 语言中的类型转换运算符太过松散。例如,请看下面的代码:

struct Data
{double data[200];
};
struct Junk
{int junk[100];
};
Data d = {2.5e33, 3.5e-19, 20.2e32};
char* pch = (char*)(&d); //type cast #1 - convert to string
char pch = char (&d);    //type cast #2 - convert address to a char
Junk* pj = (Junk*)(&d);  //type cast #3 - convert to Junk pointer

首先,上述 3 3 3 种类型转换,哪一种是有意义的?除非不讲理,否则它们中没有一个是有意义的。其次,这 3 3 3 中类型转换中哪种是允许的呢?在C语言中都是允许的。

对于这种松散情况,Stroustrup 采取的措施是,更严格地限制允许的类型转换,并添加 4 4 4 个类型转换运算符,使转换过程更规范:

  • dynamic_cast;
  • const_cast;
  • static_cast;
  • reinterpret_cast。

可以根据目的选择一个适合的运算符,而不是使用通用的类型转换。这指出了类型转换的原因,并让编译器能够检査程序的行为是否与设计者想法吻合。

1. dynamic_cast

假设 High 和 Low 是两个类,而 ph 和 pl 类型分别为 High* 和 Low*,则仅当 Low 是 High 的可访问基类(直接或间接)时,下面的语句才将一个 Low* 指针赋给 pl:

pl = dynamic_cast<Low*> ph;

否则,该语句将空指针赋给 pl。通常,该运算符的语法如下:
dynamic_cast< type-name > (expression)
该运算符的用途是,使得能够在类层次结构中进行向上转换(由于 is-a 关系,这样的类型转换是安全的),而不允许其他转换。

2. const_cast

const_cast 运算符用于执行只有一种用途的类型转换,即改变值为 const 或 volatile,其语法与 dynamic_cast 运算符相同:
const_cast< type-name > (expression)
如果类型的其他方面也被修改,则上述类型转换将出错。也就是说,除了 const 或 volatile 特征(有或无)可以不同外,type_name 和 expression 的类型必须相同。再次假设 High 和 Low 是两个类:

High bar;
const High* pbar = &bar;- - -
High* pb = const_cast<High*>(pbar);           // valid
const Low* pl = const_cast<const Low*>(pbar);// invalid

第一个类型转换使得 *pb 成为一个可用于修改 bar 对象值的指针,它删除 const 标签。第二个类型转换是非法的,因为它同时尝试将类型从 const High* 改为 const Low*。

提供该运算符的原因是,有时候可能需要这样一个值,它在大多数时候是常量,而有时又是可以修改的。在这种情况下,可以将这个值声明为 const,并在需要修改它的时候,使用 const_cast。这也可以通过通用类型转换来实现,但通用类型转换也可能同时改变类型:

High bar;
const High* pbar = &bar;- - -
High* pb = (High*)(pbar);// valid
Low* pl = (Low*)(pbar); // also valid

由于编程时可能无意间同时改变类型和常量特征,因此使用 const_cast 运算符更安全。

const_cast 不是万能的。它可以修改指向一个值的指针,但修改 const 值的结果是不确定的。以下程序阐明了这一点:

#include <iostream>
using std::cout;
using std::endl;
void change(const int* pt, int n);int main()
{int pop1 = 38383;const int pop2 = 2000;cout << "pop1, pop2: " << pop1 << ", " << pop2 << endl;change(&pop1, -103);change(&pop2, -103);cout << "pop1, pop2: " << pop1 << ", " << pop2 << endl;return 0;
}void change(const int* pt, int n)
{int* pc;pc = const_cast<int*>(pt);*pc += n;
}

const_cast 运算符可以删除 const int* pt 中的 const,使得编译器能够接收 change() 中的语句:

*pc += n;

但由于 pop2 被声明为 const,因此编译器可能禁止修改它,如下面的输出所示:

pop1, pop2: 38383, 2000
pop1, pop2: 38280, 2000

正如您看到的,调用 change() 时,修改了 pop1,但没有修改 pop2。在 change() 中,指针被声明为 const int*,因此不能用来修改指向的 int。指针 pc 删除了 const 特征,因此可用来修改指向的值,但仅当指向的值不是 const 时才行。因此,pc 可用于修改 pop1,但不能用于修改 pop2。

3. static_cast

static_cast 运算符的语法与其他类型转换符相同:
static_cast< type-name > (expression)
仅当 type_name 可被隐式转换为 expression 所属的类型或 expression 可被隐式转换为 type_name 所属的类型时,上述转换才是合法的,否则将出错。假设 High 是 Low 的基类,而 Pond 是一个无关的类,则从 High 到 Low 的转换、从 Low 到 High 的转换都是合法的,而从 Low 到 Pond 的转换是不允许的:

High bar;
Low blow;- - -
High* pb = static_cast<High*>(&blow); // valid upcast
Low* pl = static_cast<Low*>(&bar); // valid downcast
Pond* pmer = static_cast<Pond*>(&blow); // invalid, Pond unrelated

第一种转换是合法的,因为向上转换可以显式地进行。第二种转换是从基类指针到派生类指针,在不进行显式类型转换的情况下,将无法进行。但由于无需进行类型转换,便可以进行另一个方向的类型转换,因此使用 static_cast 来进行向下转换是合法的。

同理,由于无需进行类型转换,枚举值就可以被转换为整型,所以可以用 static_cast 将整型转换为枚举值。同样,可以使用 static_cast 将 double 转换为 int、将 float 转换为 long 以及其他各种数值转换。

4. reinterpret_cast

reinterpret_cast 运算符用于天生危险的类型转换。它不允许删除 const, 但会执行其他令人生厌的操作。有时程序员必须做一些依赖于实现的、令人生厌的操作,使用 reinterpret_cast 运算符可以简化对这种行为的跟踪工作。该运算符的语法与另外 3 3 3 个相同:
reinterpret_cast< type-name > (expression)
下面是一个使用示例:

struct dat {short a; short b;};
long value = 0xA224B118;
dat* pd = reinterpret_cast<dat*> (&value);
cout << hex << pd->a; // display first 2 bytes of value

通常,这样的转换适用于依赖于实现的底层编程程序,是不可移植的。例如,不同系统在存储多字节整型时,可能以不同的顺序存储其中的字节。

然而,reinterpret_cast 运算符并不支持所有的类型转换。例如,可以将指针类型转换为足以存储指针表示的整型,但不能将指针转换为更小的整型或浮点型。另一个限制是,不能将函数指针转换为数据指针,反之亦然。

在 C++ 中,普通类型转换也受到限制。基本上,可以执行其他类型转换可执行的操作,加上一些组合,如 static_castreinterpret_cast 后跟 const_cast,但不能执行其他转换。因此,下面的类型转换在 C 语言是允许的,但在 C++ 中通常不允许,因为对于大多数 C++ 实现,char 类型都太小,不能存储指针:

char ch = char (&d); // type cast #2 - convert address to a char

这些限制是合理的,如果您觉得这种限制难以忍受,可以使用 C 语言。

C++类型转换运算符(dynamic_cast, const_cast, static_cast)相关推荐

  1. 【C++ 语言】类型转换 ( 转换操作符 | const_cast | static_cast | dynamic_cast | reinterpret_cast | 字符串转换 )

    文章目录 I . const_cast 转换操作符 II . static_cast 转换操作符 III . dynamic_cast 转换操作符 IV . reinterpret_cast 转换操作 ...

  2. C++类型转换运算符 static_cast,dynamic_cast,reinterpret_cast,const_cast

    类型转换是一种让程序猿可以临时或永久性改变编译器对对象的解释机制.可改变对象解释方式的运算符称为类型转换运算符. 为何须要进行类型转换 通常为了实现使用不同环境的个人和厂商编写的模块可以相互调用和协作 ...

  3. C++四种cast转换(const_cast、static_cast、dynamic_cast、reinpreter_cast)类型转换运算符

    文章目录 cast含义 C++四种类型转换符各自应用场景(简略) 1. static_cast 2. dynamic_cast 3. reinterpret_cast 4. const_cast C+ ...

  4. C++类型转换(static_cast,dynamic_cast,const_cast和reinterpret_cast)

    一.概述 类型转换(cast)是将一种数据类型转换成另一种数据类型.例如,如果将一个整型值赋给一个浮点类型的变量,编译器会暗地里将其转换成浮点类型(即 隐式转换 ).转换是非常有用的,但是它也会带来一 ...

  5. 类型转换操作符:static_cast, dynamic_cast, const_cast, reinterpret_cast.

    呵呵,今天来好好看看着几个转换操作符的用法.以前老是看着眼熟,但是用着手生.今天决定搞定这些个东西. 在C语言中类型转换有几种方式: 1.      (expression). 在表达式外边加括号,由 ...

  6. 《C++ Primer 第五版》(第4.11-4.12节)——static_cast,const_cast和reinterpret_cast类型转换, 运算符优先级表

    1.static_cast,const_cast和reinterpret_cast类型转换 static_cast:强制的类型转换(不能用于底层的const转换),以前C语言中的强制类型转换都可以使用 ...

  7. 显式强制类型转换static_cast, dynamic_cast, const_cast, reinterpret_cast

    显式强制类型转换(cast)包括以下操作符: static_cast,  dynamic_cast, const_cast, reinterpret_cast,对各种显式类型转换解释: static_ ...

  8. 类型转换static_cast,dynamic_cast,const_cast,reinterpret_cast等

    一.隐式类型转换 系统自动进行,不需要程序开发人员介入. int m = 3 +45.6; //把小数部分截掉,也属于隐式类型转换的一种行为. doublen = 3 +45.6; 二.显示类型转换( ...

  9. C/C++中的数据类型转换()/static_cast/dynamic_cast/const_cast/reinterpret_cast

    文章目录 前言 数据类型自动转换 C语言中的强制类型转换 C++中的强制类型转换 static_cast dynamic_cast const_cast reinterpret_cast 强转关键字的 ...

最新文章

  1. 大道至简——失败也是积累
  2. VF01 BAPI :BAPI_BILLINGDOC_CREATEMULTIPLE
  3. HDU 1430 魔板(康托展开+BFS+预处理)
  4. win10右键一直转圈_Win10电脑开机一直转圈无法进入系统的解决方法
  5. publiccms中将推荐页的内容显示在页面片段中
  6. flink和kafka区别_Apache Flink和Kafka入门
  7. 【译】怎样处理 Safari 移动端对图片资源的限制
  8. MTK 驱动(4)---MTK Android Driver知识大全
  9. 经常会用到的ocr文字识别工具:Text Scanner for Mac
  10. paip.ecshop邮件模板修改一个密码找回 一个留言回复
  11. Google Earth 6 Beta版发布 (供下载地址)
  12. HTML标记由尖括号和,HTML标记
  13. 万网域名修改 DNS 方法
  14. PDF转Word图片转Word教程(附工具地址)
  15. 微前端在得物客服域的实践/那么多微前端框架,为啥我们选Qiankun + MF
  16. 艺赛旗(RPA)【服务端】修改服务器访问端口
  17. [转载] 服务器基础知识
  18. 葛冬冬:走出围墙的运筹学拓荒者
  19. 移动的台风:论matplotlib和cartopy配合的地图动画漫游
  20. flac3d6.0教程 附安装教程

热门文章

  1. KTV点歌系统(java)
  2. Windows Server 2012 R2 注册表与注册表编辑器-深博-专题视频课程
  3. java对象,属于你得地址找到了吗
  4. 成人学插画如何选培训班
  5. powerpoint2013新增哪些功能?年终总结ppt模板
  6. c语言浮点型自变量能自加自减,C语言中自加++自减--运算的数据类型可以是Float和Double么?...
  7. 北斗导航软件怎么下载? 1
  8. 下列领域中使用python可以实现的_【单选题】下列领域中,( )不是Python的主要应用领域 A. Web应用开发 B. 科学计算 C...
  9. 顶点着色器到片元着色器的过程,varying变量
  10. 利用js 获取本日 本周 本月时间代码