第 3 章 标 准 转 换
C++ 语 言 定 义 了 其 基 本 类 型 之 间 的 转 换 , 还 定 义 了 指 针 、 引 用 和 成 员 指 针 派 生 类型 的 转 换 。 这 些 转 换 被 称 为 “ 标 准 转 换 ” ( 有 关 类 型 、 标 准 类 型 和 派 生 类 型 的 更多 信 息 , 参 见 第 2 章 “ 基 本 概 念 ” 中 的 “ 类 型 ”。 )
本 章 讨 论 以 下 标 准 转 换 :
-
整 型 提 升
-
整 型 转 换
-
浮 点 转 换
-
浮 点 和 整 型 转 换
-
算 术 转 换
-
指 针 转 换
-
引 用 转 换
-
成 员 指 针 转 换
注 意 : 用 户 定 义 类 型 可 指 定 它 们 自 己 的 转 换 , 用 户 定 义 类 型 的 转 换 包 含 在 第 11 章“ 特 殊 成 员 函 数 ” 的 “ 构 造 函 数 ” 和 “ 转 换 ” 中 。
以 下 代 码 产 生 转 换 ( 在 此 例 子 中 为 整 型 提 升 ): long lnum1,lnum2;
int inum;
//inum 在 赋 值 前 提 升 为 类 型 long lnum1=inum;
//inum 在 乘 法 之 前 提 升 为 类 型 long lnum2=inum*lnum2;
注 意 : 仅 当 转 换 产 生 一 个 引 用 类 型 时 , 转 换 的 结 果 是 一 个 l 值 。 例 如 , 一 个 用 户 定义 的 转 换 说 明 为 :
operator int&()
返 回 一 个 引 用 , 它 是 一 个 l 值 。 可 是 转 换 说 明 为 :
operator int()
返 回 一 个 对 象 且 不 是 一 个 l 值 。
整 型 提 升
-
个 整 型 对 象 可 转 换 为 另 一 个 宽 整 型 ( 即 , 一 种 可 以 表 示 更 大 数 值 集 的 类 型 ) 。 这种 拓 宽 类 型 的 转 换 被 称 为 “ 整 型 提 升 ”。 使 用 整 型 提 升 , 你 可 以 在 另 一 个 整 型 类型 的 表 达 式 的 任 意 位 置 使 用 如 下 内 容 :
-
char 和 short int 类 型 的 对 象 、 文 字 和 常 量
-
枚 举 类 型
-
int 位 域
-
枚 举 器
-
C++ 提 升 是 “ 值 保 留 的 ” , 即 提 升 后 的 值 确 保 与 提 升 前 的 值 一 样 。 在 值 保 留 的 提
升 中 , 如 果 int 可 表 示 源 类 型 的 所 有 范 围 , 较 短 整 型 对 象 ( 如 位 域 或 char 类 型 对象 ) 被 提 升 为 int 类 型 。 如 果 int 不 能 表 示 值 的 所 有 范 围 , 则 对 象 被 提 升 为unsigned int 类 型 。 尽 管 这 种 策 略 与 ANSI C 中 使 用 的 是 一 样 的 , 值 保 留 转 换 并不 保 留 对 象 的 “ 符 号 性 ”。
值 保 留 提 升 和 保 留 符 号 性 的 提 升 通 常 产 生 相 同 的 结 果 , 可 是 , 如 果 被 提 升 的 对 象是 以 下 之 一 , 则 它 们 产 生 不 同 的 结 果 :
- / 、 % 、 /= 、 %= 、 < 、 <= 、 > 或 >= 的 操 作 数 之 一 。
这 些 运 算 符 确 定 结 果 依 赖 于 符 号 , 因 此 , 值 保 留 和 符 号 保 留 提 升 在 使 用 这 些 操 作数 时 产 生 不 同 的 结 果 。
- >> 或 >>= 的 左 操 作 数
这 个 运 算 符 在 执 行 移 位 操 作 时 对 待 有 符 号 量 和 无 符 号 量 是 不 同 的 。 对 有 符 号 量 , 右 移 导 致 符 号 位 进 入 空 位 ; 对 于 无 符 号 量 , 空 位 填 0 。
- 一 个 重 载 函 数 的 一 个 参 量 或 一 个 依 赖 于 参 量 匹 配 操 作 数 的 类 型 的 符号 的 重 载 运 算 符 ( 有 关 定 义 重 载 的 运 算 符 的 更 多 信 息 , 参 见 第 12 章“ 重 载 ” 中 的 “ 重 载 的 运 算 符 ” ) 。
整 型 转 换
整 型 转 换 在 整 数 类 型 之 间 进 行 , 整 数 类 型 为 char 、 int 和 long( 以 及 这 些 类 型 的short 、 signed 和 unsigned 版 本 ) 。
本 节 描 述 整 型 转 换 的 以 下 类 型 :
-
有 符 号 的 转 为 无 符 号 的
-
无 符 号 的 转 为 有 符 号 的
-
标 准 转 换
有 符 号 的 转 为 无 符 号 的
有 符 号 的 整 型 对 象 可 被 转 换 为 相 应 的 无 符 号 类 型 , 当 这 些 转 换 发 生 时 , 实 际 的 位模 式 并 没 有 改 变 , 但 是 数 的 解 释 改 变 了 , 考 虑 以 下 代 码 :
#include <iostream.h>
void main()
{
short i =-3; unsigned short u;
cout << (u= I ) << " \n " ;
}
其 输 出 结 果 如 下 :
65533
在 上 面 例 子 中 , 定 义 了 一 个 signed short 变 量 i , 且 初 始 化 为 一 个 负 数 , 表 达 式(u= i ) 使 i 在 赋 给 u 之 前 转 换 为 unsigned short 类 型 。
无 符 号 的 转 为 有 符 号 的
无 符 号 的 整 型 对 象 可 被 转 换 为 相 应 的 有 符 号 类 型 。 但 是 如 果 无 符 号 对 象 的 值 的范 围 超 出 了 有 符 号 类 型 可 表 示 范 围 , 则 这 种 转 换 会 导 致 数 据 的 误 解 释 , 如 下 例 所示 :
#include <iostream.h>
viod main()
{
short I ;
unsigned short u=65533;
cout << ( I =u) << ″ \n ″
}
其 输 出 结 果 如 下 :
-3
在 上 面 例 子 中 ,u 是 一 个 unsigned short 整 型 对 象 , 必 须 转 换 为 一 个 有 符 号 量 与表 达 式 I =u 的 求 值 相 符 , 由 于 它 的 值 在 signed short 中 不 能 正 常 表 示 , 所 以 数 据被 误 解 释 为 上 述 所 示 内 容 。
标 准 转 换
整 型 对 象 可 以 转 换 为 更 短 的 有 符 号 或 无 符 号 整 数 类 型 , 这 种 转 换 被 称 为 “ 标 准 转换 ” 。
如 果 源 对 象 的 值 超 出 了 用 更 短 的 类 型 所 表 示 的 范 围 , 则 转 换 会 导 致 数 据 丢 失 。
注 意 : 当 向 更 短 类 型 的 转 换 发 生 时 , 编 译 器 给 出 一 个 高 级 警 告 。
浮 点 转 换
-
个 浮 点 类 型 的 对 象 可 以 被 安 全 地 转 换 为 一 个 更 精 确 的 浮 点 类 型 , 也 就 是 , 该 转换 不 造 成 损 失 有 效 位 。 例 如 , 从 float 到 double 或从 double 到 long double 的转 换 是 安 全 的 , 而 且 值 没 有 变 化 。
-
个 浮 点 类 型 对 象 还 可 以 转 换 为 一 个 低 精 度 的 类 型 , 只 要 它 在 那 个 类 型 可 表 示 的范 围 内 ( 有 关 浮 点 类 型 的 范 围 参 见 第 2 章 “ 基 本 概 念 ” 中 的 “ 浮 点 数 限 制 ” ) 。如 果 源 数 值 不 能 被 精 确 地 表 示 , 则 它 可 被 转 换 为 邻 近 的 更 高 或 更 低 的 可 表 示 的值 。 如 果 这 样 的 值 不 存 在 , 结 果 是 不 确 定 的 , 考 虑 以 下 例 子 :
cout << (float)1E300 << endl;
float 类 型 可 表 示 的 最 大 值 为 3.402823466E38, 一 个 比 1E300 小 得 多 的 数 。因 此 , 该 数 被 转 换 为 无 穷 大 , 且 结 果 为 1.#INF 。
浮 点 和 整 型 的 转 换
某 些 表 达 式 能 够 导 致 浮 点 类 型 对 象 转 换 为 整 型 , 或 反 之 亦 然 。本 节 叙 述 以 下 类 型 的 浮 点 和 整 型 转 换 :
-
浮 点 到 整 型
-
整 型 到 浮 点
浮 点 到 整 型
当 浮 点 类 型 的 一 个 对 象 转 换 为 一 个 整 数 类 型 时 , 小 数 部 分 被 截 除 , 在 转 换 过 程 中不 发 生 舍 入 , 截 除 意 味 着 一 个 像 1.3 这 样 的 数 转 换 为 1, 而 -1.3 转 换 为 -1 。
整 型 到 浮 点
当 整 型 对 象 转 换 为 一 浮 点 类 型 且 源 值 不 能 被 准 确 表 示 时 , 结 果 是 邻 近 的 更 高 或 更低 的 可 表 示 的 值 。
算 术 转 换
很 多 二 进 制 运 算 符 ( 在 第 4 章 “ 表 达 式 ” 中 的 “ 带 二 进 制 运 算 符 的 表 达 式 ” 中 讨论 ) 导 致 操 作 数 的 转 换 并 以 同 样 的 方 式 产 生 结 果 , 这 些 运 算 导 致 转 换 的 方 式 被 称为 “ 常 用 的 算 术 转 换 ”。
不 同 类 型 的 操 作 数 的 算 术 转 换 的 执 行 如 表 3.1 所 示 。
表 3.1 类 型 转 换 的 条 件
满足的条件 转换
两 个 操 作 数 之 一 为 类 型 long double
前 面 的 条 件 不 满 足 , 其 中 一 个 操作数是 double 型
前 面 条 件 不 满 足 , 其 中 一 个 操作数是浮点型
前 面 条 件 不 满 足 ( 没 有 一 个 操 作数是 float 类型 )
另一个操作数被转换为类型 longdouble 另一个操作数被转换为类型 double
另一个操作数被转换为类型 float
对操作数的整型提升按如下方式执行 :
-
如 果 操 作 数 之 一 为 类 型 unsigned long, 另 一 个 操 作 数 被 转
换 为 类 型unsigned long
-
如 果 前 面 的 条 件 不 满 足 , 且 如 果 操 作数 之 一 为 类 型 long
而 另 一 个 为 类型 unsigned int, 两 个 操 作 数 都 被转换为类型 unsigned long 。
-
如 果 前 面 的 两 个 条 件 不 满 足 , 且 如 果操 作 数 之 一 为 类
型 long, 则 另 一 个操作数被转换为类型 long 。
续 表
-
如 果 前 面 的 三 个 条 件 不 满 足 , 且 如 果操 作 数 之 一 为 类 型 unsigned int, 则 另 一 个 操 作 数 被 转 换 为 类 型unsigned int 。
-
如 果 前 面 的 条 件 没 有 一 个 满 足 的 , 则两个操作数都被转换为类型 int 。
以 下 代 码 说 明 了 表 3.1 中 描 述 的 转 换 规 则 :
float fVal; double dVal; int iVal;
unsigned long ulVal;
dVal=iVal*ulVal; //iVal 转 换 为 unsigned long 类 型 ; 乘 法 的 结 果 转 换 为double 类 型 。
dVal=ulVal+fVal; //ulVal 转 换 为 float 类型 ; 加 法 的 结 果 转 换 为 double 类型 。
上 面 例 子 中 第 一 条 语 句 给 出 了 两 个 整 数 类 型 iVal 和 ulVal 的 乘 法 。 满 足 的 条 件是 没 有 一 个 操 作 数 是 浮 点 类 型 且 其 中 一 个 操 作 数 类 型 为 unsigned int, 因 此 , 另一 个 操 作 数 iVal 被 转 换 为 类 型 unsigned int。 结 果 赋 给 dVal 。 满 足 的 条 件 是一 个 操 作 数 类 型 为 double, 因 此 , 乘 法 的 unsigned int 结 果 被 转 换 为 类 型double 。
上 面 例 子 中 的 第 二 条 语 句 给 出 了 一 个 float 和 一 个 整 数 类 型 即 fVal 和 ulVal 的加 法 ,ulVal 变 量 被 转 换 为 类 型 float( 表 3.1 中 的 第 三 个 条 件 ), 加 法 的 结 果 被 转换 为 类 型 double( 表 3.1 中 的 第 二 个 条 件 ), 且 赋 给 dVal 。
指 针 转 换
在 赋 值 、 初 始 化 、 比 较 和 其 它 表 达 式 期 间 指 针 可 以 被 转 换 , 本 节 叙 述 以 下 指 针 转换 :
-
空 指 针
-
void 类 型 指 针
-
对 象 指 针
-
函 数 指 针
-
类 指 针
-
表 达 式
-
用 const 或 volatile 修 饰 的 指 针
空 指 针
等 于 0 的 一 个 整 型 常 量 表 达 式 或 造 型 转 换 为 类 型 void *的 表 达 式 , 被 转 换 为 一个 指 针 , 且 称 为 “ 空 指 针 ”。 此 指 针 确 保 与 任 意 有 效 对 象 或 函 数 的 指 针 相 比 不 相等 ( 除 了 基 本 对 象 的 指 针 , 这 种 指 针 可 以 具 有 相 同 的 偏 移 量 但 指 向 不 同 的 对 象 ) 。
void 类 型 指 针
void 类 型 指 针 可 被 转 换 为 任 何 其 它 类 型 的 指 针 , 但 必 须 用 显 式 的 类 型 造 型 ( 不 像C 语 言 )( 有 关 类 型 造 型 的 更 多 信 息 参 见 第 4 章 “ 表 达 式 ” 中 的 “ 带 显 式 类 型 转换 的 表 达 式 ” ) 。 任 意 类 型 的 指 针 可 被 隐 含 地 转 换 为 void 类 型 指 针 。
一 个 类 型 的 不 完 整 对 象 的 一 个 指 针 可 被 转 换 为 void 指 针 ( 隐 性 地 ) 并 可 以 反 回 来( 显 式 地 ), 这 种 转 换 的 结 果 等 于 源 指 针 的 值 。 一 个 对 象 如 果 被 说 明 , 但 没 有 足 够的 信 息 来 确 定 其 尺 寸 或 基 类 , 则 被 认 为 是 不 完 整 的 。
对 象 指 针
任 何 不 为 const 或 volatile 的 对 象 的 指 针 可 被 隐 式 地 转 换 为 void * 类 型 指 针 。
函 数 指 针
一 个 函 数 指 针 可 被 转 换 为 类 型 为 void *, 如 果 类 型 void * 足 够 大 可 以 保 持 那 个指 针 。
类 指 针
在 两 种 情 况 下 , 一 个 类 指 针 可 被 转 换 为 一 个 基 类 指 针 。
第 一 种 情 况 是 当 指 定 的 基 类 是 可 访 问 的 , 且 转 换 不 是 模 糊 的 ( 有 关 模 糊 的 基 类 引用 的 更 多 信 息 参 见 第 9 章 “ 派 生 类 ” 中 的 “ 多 重 基 类 ” )
一 个 基 类 是 否 可 访 问 取 决 于 派 生 中 继 承 的 种 类 , 考 虑 图 3.1 中 描 述 的 继 承 性 :
图 3.1 基 类 访 问 性 描 述 的 继 承 图
表 3.2 给 出 了 图 3.1 描 述 的 情 形 的 基 类 访 问 性 。
表 3.2 基 类 访 问 性
函数类型 |
派生 |
从 B* 到 A* 的 转 换 是 否 合 法 |
---|---|---|
外部 ( 非类范围 ) 函数 |
私有的保护的公共的 |
否否是 |
B 成员函数 ( 在 B 范围内 ) |
私有的 |
是 |
保护的 |
是 |
|
公共的 |
是 |
|
C 成员函数 ( 在 C 范围 ) |
私有的 |
否 |
保护的 |
是 |
|
公共的 |
是 |
一 个 类 指 针 可 被 转 换 为 一 个 基 类 指 针 的 第 二 种 情 况 是 当 你 使 用 显 式 类 型 转 换 的情 形 ( 有 关 显 式 类 型 转 换 的 更 多 信 息 , 参 见 第 4 章 “ 表 达 式 ” 中 的 “ 带 显 式 类 型转 换 的 表 达 式 ” ) 。
这 种 转 换 的 结 果 是 一 个 “ 子 对 象 ” 的 指 针 , 该 对 象 部 分 完 全 由 基 类 描 述 。
以 下 代 码 定 义 两 个 类 A 和 B, 其 中 B 由 A 派 生 而 来 ( 有 关 继 承 , 见 第 9 章“ 派 生 类 ”) 然 后 定 义 了 类 型 B 的 一 个 对 象 bObject, 和 指 向 对 象 的 两 个 指 针 (pA 和 pB) 。class A
{
public:
int AComponent;
int AMemberFunc();
};
Class B:public A
{
public:
int BComponent;
int BMemberFunc();
};
B bObject;
A *pA=&bObject;
B *pB=&bObject;
pA->AMemberFunc(); // 在 类 A 中 可 行
pB->AMemberFunc(); // 可 行 : 从类 A 中 继 承 而 来
pA->BMemberFunc(); // 错 误 : 不 在 类 A 中
指 针 pA 为 类 型 A*, 可 被 解 释 为 “ 指 向 类 型 A 的 一 个 对 象 的 指 针 ” ,bObject 成 员( 例 如 BComponent 和 BMemberFunc) 是 类 型 B 所 唯 一 的 , 因 此 不 能 通 过 pA 进 行 访问 ,pA 指 针 仅 仅 允 许 访 问 类 A 定 义 的 对 象 的 特 征 ( 成 员 函 数 和 数 据 ) 。
指 针 表 达 式
任 何 带 数 组 类 型 的 表 达 式 可 被 转 换 为 同 类 型 的 一 个 指 针 , 转 换 的 结 果 是 指 向 第 一个 数 组 元 素 的 指 针 。 以 下 例 子 说 明 了 这 种 转 换 :
char szPath[_MAX_PATH]; //char 类 型 的 数 组char *pszPath=szPath; // 等 于 &szPath[0]
-
个 表 达 式 结 果 是 返 回 一 特 定 类 型 的 函 数 , 可 被 转 换 为 返 回 那 个 类 型 的 函 数 的 一个 指 针 , 除 了 :
-
该 表 达 式 被 用 作 取 地 址 运 算 符 (&) 的 一 个 操 作 数 。
-
该 表 达 式 被 用 作 函 数 调 用 运 算 符 的 一 个 操 作 数 。
-
用 const 或 volatile 修 饰 的 指 针
C++ 不 提 供 const 或 volatile 类 型 到 非 const 或 volatile 的 一 个 标 准 转 换 , 但是 任 何 类 型 的 转 换 可 以 使 用 显 式 类 型 造 型 ( 包 括 不 安 全 的 转 换 ) 加 以 指 定 。
注 意 C++ 的 成 员 指 针 , 除 了 静 态 成 员 指 针 之 外 , 与 普 通 指 针 不 同 且 没 有 同 样 的 标准 转 换 。
静 态 成 员 指 针 是 普 通 指 针 且 有 与 普 通 指 针 一 样 的 转 换 ( 有 关 更 多 的 信 息 参 见 第 2 章 “ 基 本 概 念 ” 中 的 “ 类 成 员 指 针 ” ) 。
引 用 转 换
-
个 类 的 引 用 在 下 列 情 况 下 可 被 转 换 为 一 个 基 类 的 引 用 :
-
指 定 的 基 类 是 可 访 问 的 ( 正 如 本 章 前 面 的 “ 类 指 针 ” 中 定 义 的 )
-
转 换 是 非 模 糊 的 ( 有 关 模 糊 基 类 引 用 的 更 多 信 息 参 见 第 9 章 “ 派 生类 ” 中 的 “ 多 重 基 类 ” ) 。
-
转 换 的 结 果 是 表 示 基 类 的 子 对 象 的 一 个 指 针 。
有 关 引 用 的 更 多 信 息 , 参 见 第 2 章 “ 基 本 概 念 ” 中 的 “ 对 象 引 用 ”。
成 员 指 针 转 换
类 成 员 指 针 在 赋 值 、 初 始 化 、 比 较 和 其 它 表 达 式 期 间 可 被 转 换 , 本 节 描 述 了 以 下成 员 指 针 转 换 :
-
整 型 常 量 表 达 式
-
基 类 成 员 指 针
整 型 常 量 表 达 式
等 于 0 的 一 个 整 型 常 量 表 达 式 被 转 换 为 一 个 被 称 为 “ 空 指 针 ” 的 指 针 。 该 指 针确 保 与 任 意 有 效 的 对 象 或 函 数 相 比 不 相 等 ( 除 了 基 本 对 象 指 针 之 外 , 这 种 指 针 可以 具 有 相 同 的 偏 移 量 但 指 向 不 同 的 对 象 ) 。
以 下 代 码 给 出 了 类 A 的 成 员 i 的 一 个 指 针 的 定 义 。 pai 指 针 被 初 始 化 为 0, 即 空指 针 :
class A
{
public:
int i:
};
int A::*pai=0;
基 类 成 员 指 针
当 以 下 条 件 被 满 足 时 , 基 类 成 员 指 针 可 被 转 换 为 从 该 类 派 生 的 类 的 成 员 指 针 :
-
逆 转 换 , 从 派 生 类 指 针 到 基 类 指 针 , 是 可 访 问 的 。
-
派 生 类 不 从 基 类 虚 拟 地 继 承 。
当 左 操 作 数 是 一 个 成 员 指 针 时 , 右 操 作 数 必 须 为 成 员 指 针 类 型 或 为 等 于 0 的 常 量表 达 式 。
这 种 赋 值 仅 在 以 下 情 况 下 是 有 效 的 :
-
右 操 作 数 是 与 左 操 作 数 相 同 类 的 成 员 指 针 。
-
左 操 作 数 是 从 右 操 作 数 类 公 共 地 非 模 糊 地 派 生 的 类 成 员 的 一 个 指针 。