- 内容提要
- 前言
- 第 1 章 预备知识
- 第 2 章 开始学习 C++
- 第 3 章 处理数据
- 第 4 章 复合类型
- 第 5 章 循环和关系表达式
- 第 6 章 分支语句和逻辑运算符
- 第 7 章 函数——C++的编程模块
- 第 8 章 函数探幽
- 第 9 章 内存模型和名称空间
- 第 10 章 对象和类
- 第 11 章 使用类
- 第 12 章 类和动态内存分配
- 第 13 章 类继承
- 第 14 章 C++中的代码重用
- 第 15 章 友元、异常和其他
- 第 16 章 string 类和标准模板库
- 第 17 章 输入、输出和文件
- 第 18 章 探讨 C++新标准
- 附录 A 计数系统
- 附录 B C++保留字
- 附录 C ASCII 字符集
- 附录 D 运算符优先级
- 附录 E 其他运算符
- 附录 F 模板类 string
- 附录 G 标准模板库方法和函数
- 附录 H 精选读物和网上资源
- 附录 I 转换为 ISO 标准 C++
- 附录 J 复习题答案
15.5 类型转换运算符
在 C++的创始人 Bjarne Stroustrup 看来,C 语言中的类型转换运算符太过松散。例如,请看下面的代码:
首先,上述 3 种类型转换中,哪一种有意义?除非不讲理,否则它们中没有一个是有意义的。其次,这 3 种类型转换中哪种是允许的呢?在 C 语言中都是允许的。
对于这种松散情况,Stroustrop 采取的措施是,更严格地限制允许的类型转换,并添加 4 个类型转换运算符,使转换过程更规范:
- dynamic_cast;
- const_cast;
- static_cast;
- reinterpret_cast。
可以根据目的选择一个适合的运算符,而不是使用通用的类型转换。这指出了进行类型转换的原因,并让编译器能够检查程序的行为是否与设计者想法吻合。
dynamic_cast 运算符已经在前面介绍过了。总之,假设 High 和 Low 是两个类,而 ph 和 pl 的类型分别为 High *和 Low *,则仅当 Low 是 High 的可访问基类(直接或间接)时,下面的语句才将一个 Low*指针赋给 pl:
否则,该语句将空指针赋给 pl。通常,该运算符的语法如下:
该运算符的用途是,使得能够在类层次结构中进行向上转换(由于 is-a 关系,这样的类型转换是安全的),而不允许其他转换。
const_cast 运算符用于执行只有一种用途的类型转换,即改变值为 const 或 volatile,其语法与 dynamic_cast 运算符相同:
如果类型的其他方面也被修改,则上述类型转换将出错。也就是说,除了 const 或 volatile 特征(有或无)可以不同外,type_name 和 expression 的类型必须相同。再次假设 High 和 Low 是两个类:
第一个类型转换使得*pb 成为一个可用于修改 bar 对象值的指针,它删除 const 标签。第二个类型转换是非法的,因为它同时尝试将类型从 const High *改为 const Low *。
提供该运算符的原因是,有时候可能需要这样一个值,它在大多数时候是常量,而有时又是可以修改的。在这种情况下,可以将这个值声明为 const,并在需要修改它的时候,使用 const_cast。这也可以通过通用类型转换来实现,但通用转换也可能同时改变类型:
由于编程时可能无意间同时改变类型和常量特征,因此使用 const_cast 运算符更安全。
const_cast 不是万能的。它可以修改指向一个值的指针,但修改 const 值的结果是不确定的。程序清单 15.19 的简单示例阐明了这一点:
程序清单 15.19 constcast.cpp
const_cast 运算符可以删除 const int* pt 中的 const,使得编译器能够接受 change( ) 中的语句:
但由于 pop2 被声明为 const,因此编译器可能禁止修改它,如下面的输出所示:
正如您看到的,调用 change( ) 时,修改了 pop1,但没有修改 pop2。在 chang( ) 中,指针被声明为 const int *,因此不能用来修改指向的 int。指针 pc 删除了 const 特征,因此可用来修改指向的值,但仅当指向的值不是 const 时才可行。因此,pc 可用于修改 pop1,但不能用于修改 pop2。
static_cast 运算符的语法与其他类型转换运算符相同:
仅当 type_name 可被隐式转换为 expression 所属的类型或 expression 可被隐式转换为 type_name 所属的类型时,上述转换才是合法的,否则将出错。假设 High 是 Low 的基类,而 Pond 是一个无关的类,则从 High 到 Low 的转换、从 Low 到 High 的转换都是合法的,而从 Low 到 Pond 的转换是不允许的:
第一种转换是合法的,因为向上转换可以显示地进行。第二种转换是从基类指针到派生类指针,在不进行显示类型转换的情况下,将无法进行。但由于无需进行类型转换,便可以进行另一个方向的类型转换,因此使用 static_cast 来进行向下转换是合法的。
同理,由于无需进行类型转换,枚举值就可以被转换为整型,所以可以用 static_cast 将整型转换为枚举值。同样,可以使用 static_cast 将 double 转换为 int、将 float 转换为 long 以及其他各种数值转换。
reinterpret_cast 运算符用于天生危险的类型转换。它不允许删除 const,但会执行其他令人生厌的操作。有时程序员必须做一些依赖于实现的、令人生厌的操作,使用 reinterpret_cast 运算符可以简化对这种行为的跟踪工作。该运算符的语法与另外 3 个相同:
下面是一个使用示例:
通常,这样的转换适用于依赖于实现的底层编程技术,是不可移植的。例如,不同系统在存储多字节整型时,可能以不同的顺序存储其中的字节。
然而,reinterprete_cast 运算符并不支持所有的类型转换。例如,可以将指针类型转换为足以存储指针表示的整型,但不能将指针转换为更小的整型或浮点型。另一个限制是,不能将函数指针转换为数据指针,反之亦然。
在 C++中,普通类型转换也受到限制。基本上,可以执行其他类型转换可执行的操作,加上一些组合,如 static_cast 或 reinterpret_cast 后跟 const_cast,但不能执行其他转换。因此,下面的类型转换在 C 语言中是允许的,但在 C++中通常不允许,因为对于大多数 C++实现,char 类型都太小,不能存储指针:
这些限制是合理的,如果您觉得这种限制难以忍受,可以使用 C 语言。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论