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.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 的 常 量表 达 式 。

这 种 赋 值 仅 在 以 下 情 况 下 是 有 效 的 :

  • 右 操 作 数 是 与 左 操 作 数 相 同 类 的 成 员 指 针 。

  • 左 操 作 数 是 从 右 操 作 数 类 公 共 地 非 模 糊 地 派 生 的 类 成 员 的 一 个 指针 。