FY.DOC
|
|
|
- 虑 祝
- 9 years ago
- Views:
Transcription
1 高 职 高 专 21 世 纪 规 划 教 材 C++ 程 序 设 计 邓 振 杰 主 编 贾 振 华 孟 庆 敏 副 主 编 人 民 邮 电 出 版 社
2 内 容 提 要 本 书 系 统 地 介 绍 C++ 语 言 的 基 本 概 念 基 本 语 法 和 编 程 方 法, 深 入 浅 出 地 讲 述 C++ 语 言 面 向 对 象 的 重 要 特 征 : 类 和 对 象 抽 象 封 装 继 承 等 主 要 内 容 包 括 C++ 语 言 基 础 知 识 基 本 数 据 类 型 和 表 达 式 函 数 数 组 结 构 体 和 共 用 体 指 针 和 应 用 类 与 数 据 抽 象 运 算 符 重 载 继 承 性 虚 函 数 和 多 态 C++ 输 入 输 出 流 文 件 处 理 本 书 内 容 丰 富, 概 念 清 楚, 实 例 丰 富, 注 重 基 础 知 识 与 典 型 应 用 的 结 合, 系 统 性 和 应 用 性 强, 是 作 者 多 年 教 学 和 实 践 经 验 的 结 晶 本 书 语 言 通 俗 易 懂, 深 入 浅 出, 力 求 突 出 重 点, 强 调 实 际 应 用 书 中 所 有 程 序 全 部 在 Visual C 环 境 下 运 行 通 过 本 书 适 合 作 为 高 职 高 专 计 算 机 及 其 相 关 专 业 学 习 程 序 设 计 语 言 课 程 的 教 材, 也 可 作 为 广 大 计 算 机 应 用 人 员 的 自 学 参 考 书 高 职 高 专 21 世 纪 规 划 教 材 C++ 程 序 设 计 主 编 邓 振 杰 副 主 编 贾 振 华 孟 庆 敏 责 任 编 辑 潘 春 燕 人 民 邮 电 出 版 社 出 版 发 行 北 京 市 崇 文 区 夕 照 寺 街 14 号 邮 编 电 子 函 件 [email protected] 网 址 读 者 热 线 北 京 顺 义 振 华 印 刷 厂 印 刷 新 华 书 店 总 店 北 京 发 行 所 经 销 开 本 : /16 印 张 :15.75 字 数 :374 千 字 2004 年 12 月 第 1 版 印 数 :1 000 册 2004 年 12 月 北 京 第 1 次 印 刷 ISBN /TP 2230
3 编 者 的 话 伴 随 计 算 机 技 术 的 飞 速 发 展, 计 算 机 应 用 的 范 围 越 来 越 广, 计 算 机 普 及 的 程 度 越 来 越 深 入, 致 使 软 件 系 统 的 规 模 和 复 杂 性 急 剧 膨 胀, 传 统 的 面 向 过 程 程 序 设 计 已 不 能 满 足 社 会 发 展 的 需 要 巨 大 的 需 求 引 发 了 软 件 技 术 革 命, 诞 生 了 面 向 对 象 程 序 设 计 的 思 想 和 方 法 C++ 是 当 今 较 为 流 行 的 一 种 面 向 对 象 程 序 设 计 语 言, 完 全 兼 容 C 语 言, 具 有 高 效 灵 活 功 能 强 大 及 可 重 用 性 好 等 特 点 使 用 C++ 语 言 进 行 程 序 设 计 更 方 便, 软 件 维 护 更 容 易 本 书 是 作 者 在 多 年 从 事 C++ 程 序 设 计 教 学 的 基 础 上 编 写 的, 凝 聚 了 作 者 多 年 教 学 和 科 研 的 经 验 与 体 会, 具 有 很 强 的 实 用 性 和 可 读 性 本 书 针 对 学 生 在 学 习 过 程 中 容 易 出 现 的 问 题 进 行 讲 解, 通 过 大 量 程 序 示 例 进 行 启 发 式 教 学, 重 点 培 养 学 生 分 析 问 题 和 解 决 问 题 的 能 力 本 书 根 据 高 职 高 专 的 教 学 特 点, 力 求 语 言 通 俗 易 懂, 概 念 明 确, 尽 量 避 免 枯 燥 的 理 论 讲 授, 力 争 将 复 杂 的 概 念 示 例 化, 将 抽 象 的 理 论 形 象 化, 用 大 量 的 程 序 示 例 来 帮 助 读 者 理 解 概 念 和 理 论, 使 读 者 逐 步 掌 握 C++ 语 言 的 完 整 体 系 本 书 内 容 全 面, 在 内 容 安 排 上 由 浅 入 深, 从 最 简 单 的 概 念 开 始, 循 序 渐 进, 突 出 实 用 性, 使 读 者 在 学 完 本 书 后 能 够 真 正 学 以 致 用 本 书 选 材 适 当, 定 位 准 确, 示 例 丰 富, 重 点 突 出, 书 中 给 出 的 所 有 例 题 程 序 均 在 Visual C 集 成 环 境 中 运 行 通 过 本 书 还 可 以 提 供 电 子 教 案 和 所 有 程 序 的 源 代 码 全 书 以 介 绍 C++ 语 言 面 向 对 象 程 序 设 计 的 思 想 和 方 法 为 主, 共 12 章, 主 要 内 容 包 括 C++ 语 言 概 述 基 本 数 据 类 型 和 表 达 式 函 数 数 组 结 构 体 和 共 用 体 指 针 和 引 用 类 和 数 据 抽 象 运 算 符 重 载 继 承 性 虚 函 数 和 多 态 性 C++ 输 入 输 出 流 文 件 处 理 等 本 书 由 邓 振 杰 担 任 主 编, 贾 振 华 孟 庆 敏 任 副 主 编 各 章 编 写 分 工 如 下 : 第 章 由 邓 振 杰 编 写, 第 4 章 由 陈 征 峰 编 写, 第 章 由 贾 振 华 编 写, 第 11 和 12 章 由 孟 庆 敏 编 写, 斯 庆 巴 拉 金 永 涛 曲 凤 娟 邵 温 刘 立 媛 王 静 和 李 京 辉 也 参 加 了 部 分 内 容 的 编 写 以 及 大 纲 讨 论 和 文 稿 整 理 工 作 全 书 由 邓 振 杰 负 责 统 稿 由 于 作 者 水 平 有 限, 书 中 难 免 出 现 一 些 错 误 和 不 妥 之 处, 敬 请 读 者 批 评 指 正 编 者 2005 年 1 月
4 目 录 第 1 章 C++ 概 述 面 向 对 象 程 序 设 计 基 本 概 念 传 统 程 序 设 计 及 其 局 限 性 面 向 对 象 程 序 设 计 及 其 优 点 面 向 对 象 程 序 设 计 的 特 点 面 向 对 象 程 序 设 计 语 言 的 发 展 C++ 的 发 展 和 特 点 C++ 的 发 展 C++ 的 特 点 C++ 与 C 语 言 的 关 系 C++ 程 序 基 本 结 构 C++ 程 序 基 本 结 构 C++ 程 序 的 书 写 格 式 C++ 程 序 的 上 机 实 现 编 辑 编 译 连 接 运 行 12 习 题 17 第 2 章 基 本 数 据 类 型 和 表 达 式 词 法 符 号 标 识 符 关 键 字 常 量 运 算 符 分 隔 符 基 本 数 据 类 型 常 量 与 变 量 常 量 变 量 运 算 符 和 表 达 式 24
5 2 C++ 程 序 设 计 运 算 符 表 达 式 控 制 语 句 表 达 式 语 句 复 合 语 句 选 择 语 句 循 环 语 句 转 移 语 句 39 习 题 41 第 3 章 函 数 函 数 的 定 义 函 数 定 义 函 数 原 型 函 数 调 用 函 数 调 用 的 概 念 函 数 调 用 的 参 数 传 递 函 数 的 嵌 套 调 用 和 递 归 调 用 函 数 main() 的 参 数 局 部 变 量 和 全 局 变 量 局 部 变 量 全 局 变 量 内 联 函 数 函 数 重 载 56 习 题 57 第 4 章 数 组 一 维 数 组 的 定 义 和 数 组 元 素 的 引 用 一 维 数 组 的 定 义 一 维 数 组 的 初 始 化 一 维 数 组 元 素 的 引 用 一 维 数 组 的 使 用 二 维 数 组 的 定 义 和 数 组 元 素 的 引 用 二 维 数 组 的 定 义 二 维 数 组 元 素 的 初 始 化 二 维 数 组 元 素 的 引 用 二 维 数 组 的 使 用 字 符 数 组 字 符 数 组 的 定 义 及 初 始 化 68
6 目 录 字 符 串 处 理 函 数 字 符 数 组 的 应 用 71 习 题 72 第 5 章 结 构 体 和 共 用 体 结 构 体 结 构 体 的 定 义 结 构 体 变 量 的 定 义 结 构 体 变 量 的 初 始 化 结 构 体 变 量 的 使 用 结 构 体 数 组 共 用 体 共 用 体 共 用 体 变 量 的 定 义 共 用 体 变 量 的 使 用 84 习 题 85 第 6 章 指 针 和 引 用 指 针 指 针 的 概 念 指 针 与 数 组 指 针 与 字 符 串 指 针 与 函 数 动 态 内 存 分 配 引 用 引 用 的 概 念 引 用 与 函 数 105 习 题 107 第 7 章 类 与 数 据 抽 象 类 的 定 义 对 象 的 定 义 对 象 的 定 义 对 象 成 员 的 表 示 方 法 构 造 函 数 和 析 构 函 数 构 造 函 数 和 析 构 函 数 缺 省 构 造 函 数 和 缺 省 析 构 函 数 拷 贝 初 始 化 构 造 函 数 成 员 函 数 的 特 征 成 员 函 数 的 重 载 119
7 4 C++ 程 序 设 计 参 数 的 缺 省 值 静 态 成 员 静 态 数 据 成 员 静 态 成 员 函 数 友 元 友 元 函 数 友 元 类 对 象 的 指 针 和 对 象 的 引 用 对 象 的 指 针 this 指 针 对 象 引 用 对 象 数 组 常 类 型 常 指 针 和 常 引 用 常 成 员 函 数 常 数 据 成 员 139 习 题 140 第 8 章 运 算 符 重 载 概 述 运 算 符 重 载 的 一 般 规 则 一 些 特 殊 操 作 符 的 重 载 一 元 运 算 符 重 载 二 元 运 算 符 重 载 151 习 题 154 第 9 章 继 承 性 基 类 和 派 生 类 派 生 类 的 定 义 继 承 方 式 单 继 承 单 继 承 中 的 成 员 访 问 权 限 构 造 函 数 和 析 构 函 数 多 继 承 多 继 承 的 概 念 多 继 承 的 构 造 函 数 和 析 构 函 数 二 义 性 问 题 虚 基 类 虚 基 类 的 引 入 和 说 明 169
8 目 录 虚 基 类 的 构 造 函 数 虚 基 类 的 应 用 171 习 题 174 第 10 章 虚 函 数 和 多 态 性 虚 函 数 虚 函 数 的 定 义 纯 虚 函 数 抽 象 类 虚 析 构 函 数 多 态 多 态 的 含 义 多 态 的 应 用 185 习 题 187 第 11 章 C++ 输 入 / 输 出 流 输 入 / 输 出 流 的 概 念 输 出 流 基 本 输 出 操 作 输 出 格 式 控 制 输 入 流 基 本 输 入 操 作 输 入 格 式 控 制 208 习 题 208 第 12 章 文 件 处 理 文 件 简 介 文 件 和 流 顺 序 文 件 的 访 问 建 立 顺 序 访 问 文 件 读 取 顺 序 文 件 中 的 数 据 更 新 顺 序 文 件 中 的 数 据 随 机 文 件 的 访 问 建 立 随 机 访 问 文 件 读 取 随 机 文 件 中 的 数 据 数 据 写 入 随 机 文 件 221 习 题 222 第 13 章 实 训 223
9 6 C++ 程 序 设 计 13.1 实 训 1 熟 悉 Visual C 集 成 开 发 环 境 实 训 2 简 单 C++ 程 序 设 计 实 训 3 控 制 语 句 实 训 4 函 数 的 应 用 实 训 5 数 组 的 使 用 实 训 6 结 构 体 和 共 用 体 实 训 7 指 针 的 使 用 实 训 8 类 与 数 据 抽 象 实 训 9 运 算 符 重 载 实 训 10 继 承 性 和 派 生 实 训 11 虚 函 数 和 多 态 性 实 训 12 输 入 / 输 出 流 实 训 13 文 件 处 理 239 参 考 文 献 240
10 1 章 C++ 概 述 20 世 纪 90 年 代 以 来, 面 向 对 象 程 序 设 计 (Object Oriented Programming,OOP) 成 为 计 算 机 程 的 主 流, 其 设 计 思 想 已 经 被 越 来 越 多 的 软 件 设 计 人 员 所 接 受 C++ 语 言 完 全 兼 容 C 语 言, 不 仅 C 语 言 灵 活 高 效 功 能 强 大 和 可 移 植 性 好 等 优 点, 而 且 引 入 了 面 向 对 象 程 序 设 计 的 思 想 和 机 制, 大 程 度 地 提 高 编 程 能 力, 减 少 软 件 维 护 的 开 销, 增 强 软 件 的 可 扩 展 性 和 可 重 用 性 因 此,C++ 出 现 就 受 到 了 广 大 用 户 的 青 睐, 版 本 不 断 更 新, 功 能 不 断 完 善, 迅 速 成 为 面 向 对 象 程 序 设 计 的 言 1.1 面 向 对 象 程 序 设 计 基 本 概 念 1. 对 象 现 实 世 界 中 客 观 存 在 的 任 何 事 物 都 可 以 称 之 为 对 象, 它 可 以 是 有 形 的 具 体 事 物, 如 一 本 书 一 或 一 辆 汽 车 等, 也 可 以 是 一 个 无 形 的 抽 象 事 物, 如 一 次 演 出 或 一 场 球 赛 等 对 象 是 构 成 世 界 的 立 单 位, 可 以 很 简 单, 也 可 以 很 复 杂, 复 杂 的 对 象 可 以 由 简 单 的 对 象 构 成 现 实 世 界 中 的 对 象 既 具 有 静 态 的 属 性 ( 或 称 状 态 ), 又 具 有 动 态 的 行 为 ( 或 称 操 作 ) 例 如, 每 有 姓 名 性 别 年 龄 身 高 和 体 重 等 属 性, 都 有 吃 饭 走 路 睡 觉 和 学 习 等 行 为 所 以, 现 实 的 对 象 一 般 可 以 表 示 为 : 属 性 + 行 为 现 实 世 界 中 的 对 象 一 般 具 有 以 下 特 性 (1) 每 一 个 对 象 必 须 有 一 个 名 字 以 区 别 于 其 他 对 象 (2) 用 属 性 来 描 述 对 象 的 某 些 特 征 (3) 有 一 组 操 作, 每 个 操 作 决 定 对 象 的 一 种 行 为 在 面 向 对 象 程 序 设 计 中, 对 象 是 由 对 象 名 一 组 属 性 数 据 和 一 组 操 作 封 装 在 一 起 构 成 的 实 体 性 数 据 是 对 象 固 有 特 征 的 描 述, 操 作 是 对 这 些 属 性 数 据 施 加 的 动 态 行 为, 是 一 系 列 的 实 现 步 骤 称 之 为 方 法 对 象 通 过 封 装 实 现 了 信 息 隐 藏, 对 象 与 外 部 是 通 过 操 作 接 口 联 系 的, 操 作 的 具 体 实 现 步 骤 外 部 见 的 封 装 的 目 的 就 是 防 止 非 法 访 问, 操 作 接 口 提 供 了 这 个 对 象 所 具 有 的 功 能 打 个 形 象 的 比 喻, 一 个 对 象 就 好 比 一 台 录 音 机 人 们 使 用 录 音 机 时 通 过 播 放 录 音 暂 停 停 止 以 及 快 退 等 按 键 就 可 以 操 作 录 音 机, 录 音 机 就 会 完 成 相 应 的 工 作 人 们 通 过 安 装 在 录 音 机 表 面
11 C++ 程 序 设 计 音 机 所 具 有 的 功 能, 我 们 只 能 借 助 于 这 些 按 键 实 现 对 录 音 机 的 操 作 如 果 把 对 象 看 作 录 音 机, 则 录 音 机 的 功 率 声 道 数 及 电 源 电 压 等 就 相 当 于 对 象 的 属 性, 放 音 暂 停 等 动 作 就 相 当 于 对 象 的 操 作, 而 它 的 按 键 就 相 当 于 对 象 的 接 口 事 实 上, 操 作 和 属 性 数 据 在 对 象 内 部 的, 一 个 对 象 就 相 当 于 一 个 黑 盒 子, 表 示 对 象 特 征 的 属 性 数 据 和 实 现 对 象 操 作 的 代 装 在 这 个 黑 盒 子 里 面, 外 界 是 看 不 见 的, 更 不 能 从 外 面 去 访 问 和 修 改 这 些 数 据 和 代 码 当 在 程 序 设 计 中 使 用 对 象 时, 只 能 通 过 对 象 与 外 部 的 接 口 来 操 作 它, 接 口 就 是 对 象 对 外 公 开 的 就 像 只 能 通 过 按 键 来 操 作 录 音 机 一 样 这 样 不 仅 使 对 象 的 操 作 变 得 简 单 方 便, 而 且 具 有 很 高 性 和 可 靠 性 2. 类 在 现 实 世 界 中, 类 是 一 组 具 有 相 同 属 性 和 操 作 的 对 象 的 抽 象 例 如, 张 三 李 四 和 王 五 等 是 一 体 的 人, 虽 然 每 个 人 的 性 格 爱 好 相 貌 及 职 业 等 各 不 相 同, 但 他 们 的 基 本 特 征 都 是 相 同 的, 相 似 的 生 理 构 造 和 动 作 行 为 ( 吃 饭 睡 觉 和 说 话 等 ), 故 可 以 把 他 们 统 称 为 人 类, 而 张 三 王 五 等 每 一 个 人 只 是 人 类 的 一 个 实 例 对 象 类 和 对 象 之 间 是 抽 象 与 具 体 的 关 系, 类 是 对 很 多 的 对 象 进 行 抽 象 的 结 果, 一 个 对 象 是 类 的 一 个 例 如, 汽 车 是 一 个 类, 它 是 由 成 千 上 万 个 具 体 的 汽 车 抽 象 而 来 的 一 般 概 念, 而 桑 塔 纳 200 以 看 作 是 汽 车 类 的 一 个 实 例 对 象 在 面 向 对 象 程 序 设 计 中, 类 是 具 有 相 同 属 性 数 据 和 操 作 的 对 象 的 集 合, 它 是 对 一 类 对 象 的 抽 象 类 是 创 建 对 象 的 模 板, 它 包 含 着 所 创 建 对 象 的 状 态 描 述 和 方 法 的 定 义, 一 般 是 先 声 明 类, 再 由 其 对 象 按 照 这 个 模 板 创 建 的 一 个 个 具 体 的 实 例, 就 是 对 象 这 个 过 程 就 好 像 用 木 模 来 制 作 月, 把 事 先 揉 好 的 面 塞 进 木 模 里, 将 木 模 反 扣 在 桌 上, 一 个 漂 亮 的 图 案 就 出 现 在 月 饼 上, 这 样, 模 就 可 以 制 造 出 一 个 个 图 案 一 模 一 样 的 月 饼 这 个 木 模 就 好 比 是 类, 一 个 一 个 的 月 饼 就 好 比 建 的 一 个 个 对 象 3. 消 息 现 实 世 界 中 的 对 象 不 是 一 个 个 孤 立 的 实 体, 它 们 之 间 存 在 着 各 种 各 样 的 联 系 同 样, 在 面 向 对 设 计 中, 对 象 之 间 也 需 要 联 系, 我 们 称 为 对 象 的 交 互 在 面 向 对 象 程 序 设 计 中, 当 要 求 一 个 对 象 做 某 一 操 作 时, 就 向 该 对 象 发 送 一 个 相 应 的 消 息 一 向 另 一 个 对 象 发 出 的 请 求 被 称 为 消 息 当 对 象 接 收 到 发 给 它 的 消 息 时, 就 调 用 有 关 的 方 法, 应 的 操 作 这 种 对 象 与 对 象 之 间 通 过 消 息 进 行 相 互 联 系 的 机 制, 就 叫 做 消 息 传 递 机 制 面 向 对 设 计 通 过 消 息 传 递 来 实 现 对 象 的 交 互 4. 方 法 方 法 就 是 对 象 所 能 执 行 的 操 作 方 法 包 括 接 口 和 方 法 体 两 部 分 方 法 的 接 口 就 是 消 息 的 模 式 诉 用 户 如 何 调 用 该 方 法 ; 方 法 体 则 是 实 现 操 作 的 一 系 列 步 骤, 也 就 是 一 段 程 序 代 码 消 息 和 方 法 的 关 系 是 : 对 象 接 收 到 其 他 对 象 的 消 息, 就 调 用 相 应 的 方 法 ; 反 之, 有 了 合 适 的 方 法 才 能 响 应 相 应 的 消 息 所 以, 消 息 模 式 和 方 法 接 口 应 该 是 一 致 的, 只 要 方 法 接 口 保 持 不 变, 方 改 变 就 不 会 影 响 方 法 的 调 用
12 第 1 章 C++ 概 述 传 统 程 序 设 计 及 其 局 限 性 20 世 纪 50 年 代 初 的 程 序 都 是 用 机 器 语 言 和 汇 编 语 言 编 写 的, 使 程 序 设 计 相 当 麻 烦, 严 重 影 响 机 的 普 及 应 用 20 世 纪 50 年 代 中 期 出 现 了 高 级 程 序 设 计 语 言 FORTRAN, 它 在 计 算 机 程 序 设 计 语 言 发 展 史 上 时 代 的 意 义 该 语 言 引 进 了 许 多 重 要 的 程 序 设 计 概 念, 如 变 量 数 组 循 环 及 条 件 分 支 等 但 是 言 在 使 用 中 也 发 现 了 一 些 不 足, 例 如 不 同 部 分 的 相 同 变 量 名 容 易 发 生 混 淆 等 20 世 纪 50 年 代 后 期, 高 级 语 言 Algol 60 的 设 计 者 决 定 在 程 序 段 内 部 对 变 量 实 行 隔 离, 提 出 了 的 思 想, 由 Begin End 来 实 现 块 结 构, 这 样 此 块 内 的 变 量 就 不 会 和 其 他 块 内 的 同 名 变 量 混 淆 据 实 行 了 保 护 后 来, 随 着 计 算 机 应 用 的 日 益 广 泛, 一 系 列 不 同 风 格 的 为 不 同 对 象 服 务 的 程 序 设 计 语 言 出 现 了 COBOL 和 Pascal 等 高 级 语 言 的 蓬 勃 发 展, 促 使 编 译 和 形 式 语 言 理 论 日 趋 完 善 但 就 整 个 程 序 法 而 言, 并 无 实 质 性 的 突 破 20 世 纪 60 年 代 末 到 70 年 代 初, 出 现 了 大 型 的 软 件 系 统, 如 操 作 数 据 库 管 理 系 统 等, 这 给 程 序 设 计 带 来 了 许 多 新 的 问 题 大 型 软 件 系 统 的 研 制 需 要 花 费 大 量 的 物 力, 但 编 写 出 来 的 软 件 可 靠 性 差, 错 误 多, 难 以 维 护, 已 经 到 了 程 序 员 无 法 控 制 的 地 步, 于 了 软 件 危 机 1969 年,E.W.Dijkstra 首 先 提 出 了 结 构 化 程 序 设 计 的 概 念, 他 强 调 了 从 程 序 结 构 和 风 格 上 序 设 计, 对 软 件 危 机 起 了 很 大 的 缓 解 作 用 结 构 化 程 序 设 计 的 程 序 代 码 是 按 顺 序 执 行 的, 完 整 的 控 制 结 构, 函 数 之 间 的 参 数 按 一 定 规 则 传 递, 不 提 倡 使 用 全 局 变 量, 程 序 设 计 的 首 要 问 设 计 过 程 因 此, 结 构 化 程 序 设 计 仍 是 面 向 过 程 的 程 序 设 计 到 20 世 纪 70 年 代 末, 结 构 化 程 序 设 计 方 法 有 了 很 大 的 发 展, 但 由 于 程 序 规 模 越 来 越 大, 数 据 这 些 数 据 的 方 法 之 间 的 分 离 往 往 使 程 序 变 得 难 以 理 解, 单 纯 的 面 向 过 程 的 程 序 设 计 不 适 宜 于 大 序 开 发, 已 不 能 满 足 要 求, 因 此 出 现 了 模 块 化 程 序 设 计 模 块 化 程 序 设 计 将 软 件 划 分 成 若 干 个 可 单 独 命 名 和 编 址 的 部 分, 称 之 为 模 块 模 块 化 程 序 设 计 思 路 是 自 顶 向 下, 逐 步 求 精, 其 程 序 结 构 是 按 功 能 划 分 成 若 干 个 基 本 模 块, 各 模 块 之 间 尽 可 能 简 单, 在 功 能 上 相 对 独 立 模 块 和 模 块 之 间 隔 离, 其 他 模 块 不 能 访 问 这 个 模 块 的 内 部 信 息 些 信 息 对 模 块 外 部 是 不 透 明 的, 只 能 通 过 严 格 定 义 的 接 口 对 模 块 进 行 访 问 模 块 化 程 序 设 计 将 数 据 结 构 和 相 应 算 法 集 中 在 一 个 模 块 中, 提 出 了 数 据 结 构 + 算 法 = 程 序 设 计 序 设 计 方 法 模 块 化 能 够 有 效 地 管 理 和 维 护 软 件 研 发, 能 够 有 效 地 分 解 和 处 理 复 杂 问 题, 这 使 化 程 序 设 计 方 法 普 遍 被 人 们 接 受 但 它 仍 是 一 种 面 向 过 程 的 程 序 设 计 方 法, 程 序 员 必 须 时 刻 考 处 理 数 据 的 格 式, 对 不 同 格 式 的 数 据 做 相 同 处 理 或 对 相 同 数 据 格 式 做 不 同 处 理 都 要 重 新 编 程, 重 用 性 不 好 综 上 所 述, 随 着 计 算 机 技 术 大 规 模 地 推 广, 人 们 对 计 算 机 软 件 的 功 能 要 求 越 来 越 多, 对 软 件 的 求 越 来 越 高, 传 统 的 程 序 设 计 已 不 能 满 足 这 些 日 益 增 长 的 需 要, 其 局 限 性 主 要 表 现 在 以 下 几 个 1. 传 统 程 序 设 计 开 发 的 软 件 生 产 效 率 低 下 从 1946 年 世 界 上 第 一 台 电 子 计 算 机 问 世 以 来, 计 算 机 硬 件 的 发 展 已 经 历 了 电 子 管 晶 体 管
13 C++ 程 序 设 计 费 用 高 硬 件 生 产 之 所 以 效 率 高, 主 要 原 因 是 其 生 产 方 式 已 由 分 立 元 件 一 级 的 设 计 发 展 到 芯 片 ( 模 集 成 电 路 ) 一 级 的 设 计, 硬 件 重 用 性 很 好, 便 于 实 现 生 产 过 程 的 工 程 化 和 自 动 化, 生 产 效 率 高 了 然 而, 传 统 的 程 序 设 计 语 言 尽 管 经 历 了 从 低 级 语 言 到 高 级 语 言 的 发 展, 但 其 程 序 设 计 的 主 要 工 围 绕 设 计 解 题 过 程 来 进 行 的, 故 称 为 面 向 过 程 的 程 序 设 计, 传 统 的 程 序 设 计 语 言 也 称 为 过 程 性 这 种 软 件 生 产 方 式 仍 是 采 用 原 始 方 式 进 行 的, 程 序 设 计 还 是 从 语 句 一 级 开 始, 软 件 生 产 缺 乏 可 构 件, 软 件 的 重 用 问 题 没 有 得 到 很 好 的 解 决, 导 致 软 件 生 产 的 工 程 化 和 自 动 化 屡 屡 受 阻 复 杂 性 也 是 影 响 软 件 生 产 效 率 的 重 要 因 素 随 着 计 算 机 应 用 范 围 越 来 越 广, 软 件 的 规 模 越 来 越 大 决 的 问 题 也 越 来 越 复 杂 传 统 程 序 设 计 的 是 数 据 与 数 据 的 操 作 分 离, 而 且 对 同 一 数 据 的 操 作 往 在 程 序 的 不 同 地 方 这 样, 如 果 一 个 或 多 个 数 据 的 结 构 发 生 变 化, 这 种 变 化 将 波 及 程 序 的 许 多 甚 至 遍 及 整 个 程 序, 致 使 许 多 函 数 和 过 程 需 要 重 写, 严 重 时 会 导 致 整 个 程 序 的 崩 溃 因 此, 程 杂 性 对 传 统 程 序 设 计 是 一 个 很 棘 手 的 问 题, 也 是 传 统 程 序 设 计 难 于 有 根 本 性 突 破 的 重 要 原 因 软 件 维 护 是 软 件 生 命 周 期 中 最 后 一 个 环 节 传 统 程 序 设 计 中 数 据 与 数 据 的 操 作 分 离 的 结 构, 使 数 据 和 处 理 数 据 的 操 作 过 程 要 花 费 大 量 的 时 间 和 精 力, 严 重 地 影 响 了 软 件 的 生 产 效 率 总 之, 要 提 高 软 件 的 生 产 效 率, 就 必 须 很 好 地 解 决 软 件 的 重 用 性 复 杂 性 和 可 维 护 性 问 题, 但 统 程 序 设 计 无 法 解 决 的 2. 传 统 程 序 设 计 难 以 应 付 庞 大 的 信 息 量 和 多 样 的 信 息 类 型 当 前, 计 算 机 要 处 理 的 数 据 已 从 简 单 的 数 字 和 字 符, 发 展 为 具 有 多 种 格 式 的 多 媒 体 数 据, 如 文 本 视 频 图 形 图 像 和 动 画 等, 描 述 的 问 题 从 单 纯 的 计 算 问 题 发 展 到 复 杂 的 自 然 现 象 和 社 会 现 于 是, 计 算 机 要 处 理 的 信 息 量 和 信 息 类 型 迅 速 增 加, 这 就 要 求 程 序 语 言 有 更 强 大 的 信 息 处 理 而 这 是 传 统 程 序 设 计 无 法 办 到 的 3. 传 统 程 序 设 计 难 以 适 应 各 种 新 环 境 当 前, 在 计 算 机 应 用 技 术 中, 并 行 处 理 分 布 式 处 理 网 络 和 多 机 系 统 应 用 等 已 经 成 为 程 序 设 流, 这 就 要 求 系 统 包 括 一 些 具 有 独 立 数 据 处 理 能 力 的 节 点, 节 点 之 间 有 通 信 机 制, 即 能 以 消 息 行 联 络, 而 这 也 是 传 统 程 序 设 计 无 能 为 力 的 显 然, 传 统 程 序 设 计 已 不 能 满 足 计 算 机 技 术 迅 猛 发 展 的 需 要, 大 规 模 软 件 开 发 迫 切 需 要 一 种 全 序 设 计 方 法 来 满 足 需 要 面 向 对 象 程 序 设 计 及 其 优 点 在 程 序 设 计 中 各 种 概 念 和 方 法 日 益 成 熟 的 基 础 上, 就 如 何 超 越 程 序 的 复 杂 性 障 碍, 如 何 在 计 算 中 自 然 地 表 示 客 观 世 界 等 问 题, 人 们 提 出 了 面 向 对 象 的 程 序 设 计 方 法 它 不 是 以 过 程 为 中 心, 对 象 为 中 心 环 节, 提 出 了 对 象 + 消 息 = 程 序 设 计 的 理 论, 使 人 们 对 复 杂 系 统 的 认 识 过 程 与 系 序 设 计 实 现 过 程 尽 可 能 地 一 致 面 向 对 象 程 序 设 计 是 程 序 设 计 发 展 史 上 的 一 个 重 要 里 程 碑, 它 从 根 本 上 改 变 了 人 们 以 往 设 计 程 维 方 式, 从 而 使 程 序 设 计 摆 脱 了 具 体 的 数 据 格 式 和 过 程 的 束 缚, 将 精 力 集 中 在 要 处 理 对 象 的 设 究 上, 极 大 地 减 少 了 软 件 开 发 的 复 杂 性, 提 高 了 软 件 开 发 的 效 率 面 向 对 象 程 序 设 计 摒 弃 了 传
14 第 1 章 C++ 概 述 5 括 抽 象 和 继 承 等 ), 是 一 种 全 新 的 进 行 程 序 设 计 的 思 想 体 系 它 将 数 据 及 对 数 据 的 操 作 集 中 在 作 为 一 个 相 互 依 存, 不 可 分 割 的 整 体 来 处 理, 采 用 数 据 抽 象 和 信 息 隐 藏 技 术 加 入 了 类 及 其 继 对 象 以 类 为 模 板 被 创 建, 系 统 由 对 象 组 成, 对 象 经 历 一 系 列 的 状 态 变 化 以 完 成 任 务 在 面 向 对 设 计 中, 首 要 的 任 务 是 设 计 类, 每 个 类 应 设 置 足 够 的 操 作, 并 利 用 继 承 机 制 显 示 共 享 相 同 的 代 码 可 重 用 性 好 面 向 对 象 程 序 设 计 主 要 有 以 下 优 点 1. 可 提 高 程 序 代 码 的 重 用 性 面 向 对 象 程 序 设 计 中 对 象 所 具 有 的 封 装 性 和 信 息 隐 藏 等 特 性, 使 得 对 象 内 部 实 现 与 外 界 隔 离, 强 的 独 立 性, 可 以 作 为 一 个 可 重 用 的 程 序 构 件, 供 同 类 程 序 直 接 使 用 面 向 对 象 程 序 设 计 中 的 继 承 机 制 不 仅 使 子 类 可 以 重 用 其 父 类 的 数 据 和 程 序 代 码, 而 且 可 以 在 父 础 上 直 接 修 改 和 扩 充 这 种 修 改 并 不 影 响 对 原 有 类 的 使 用, 就 像 使 用 集 成 电 路 (IC) 构 建 硬 件 一 样, 可 以 方 便 地 利 用 类 来 构 建 软 件 系 统 因 此, 有 人 把 类 称 为 软 件 IC 2. 可 控 制 程 序 的 复 杂 性 面 向 对 象 程 序 设 计 采 用 了 数 据 抽 象 和 信 息 隐 藏 技 术, 把 数 据 和 对 数 据 的 操 作 封 装 在 类 中, 作 为 存 不 可 分 割 的 整 体 来 处 理 这 样, 在 程 序 中 任 何 要 访 问 这 些 数 据 的 地 方, 只 要 简 单 地 通 过 消 和 调 用 方 法 就 可 以 实 现 数 据 访 问, 有 效 地 控 制 了 程 序 的 复 杂 性 3. 可 改 善 程 序 的 可 维 护 性 在 面 向 对 象 程 序 设 计 中, 对 象 的 操 作 只 能 通 过 消 息 传 递 来 实 现 所 以, 只 要 消 息 模 式 即 对 应 的 口 不 变, 方 法 体 的 任 何 修 改 都 不 会 导 致 发 送 消 息 的 程 序 修 改, 这 显 然 给 程 序 的 维 护 带 来 了 方 便, 类 的 封 装 和 信 息 隐 藏 机 制 使 得 外 界 不 可 能 对 类 中 的 数 据 和 程 序 代 码 进 行 非 法 操 作, 这 也 大 大 程 序 出 错 的 可 能 性 4. 能 更 好 地 支 持 大 型 程 序 设 计 在 开 发 一 个 大 型 系 统 时, 应 对 任 务 进 行 明 确 的 严 格 划 分, 使 每 个 程 序 员 了 解 自 己 要 做 的 工 作 以 人 的 接 口, 方 便 每 个 程 序 员 独 立 地 设 计 调 试 自 己 负 责 的 模 块, 使 各 个 模 块 能 够 顺 利 地 应 用 到 统 中 面 向 对 象 程 序 设 计 中 的 类 是 一 个 抽 象 的 数 据 类 型, 所 以 类 作 为 一 个 程 序 模 块, 比 通 常 的 子 程 序 性 强 得 多, 面 向 对 象 程 序 设 计 又 引 入 了 动 态 连 接 和 继 承 等 机 制, 可 以 更 好 地 支 持 大 型 程 序 设 计 5. 增 强 了 计 算 机 处 理 信 息 的 范 围 面 向 对 象 程 序 设 计 模 拟 人 类 考 虑 问 题 和 认 识 世 界 的 方 式, 代 表 了 计 算 机 程 序 设 计 的 全 新 思 维 这 种 方 法 把 描 述 事 物 静 态 属 性 的 数 据 结 构 和 表 示 事 物 动 态 行 为 的 操 作 放 在 一 起 构 成 一 个 整 体, 自 然 地 表 示 客 观 世 界 的 实 体 用 类 来 直 接 描 述 现 实 世 界 中 的 类 型, 可 使 计 算 机 系 统 的 描 述 和 处 理 的 对 象 从 数 据 扩 展 到 现 实 世 种 事 物, 这 将 大 大 扩 展 计 算 机 系 统 能 够 处 理 的 信 息 量 和 信 息 类 型 6. 能 很 好 地 适 应 新 环 境 面 向 对 象 程 序 设 计 中 的 对 象 消 息 传 递 等 思 想 和 机 制, 与 并 行 处 理 分 布 式 处 理 网 络 和 多 机 用 等 恰 好 吻 合, 可 以 开 发 出 适 应 这 些 新 环 境 的 软 件 系 统 面 向 对 象 程 序 设 计 也 影 响 到 计 算 机 硬 系 结 构, 现 在 已 经 有 人 开 始 研 究 直 接 支 持 对 象 概 念 的 面 向 对 象 计 算 机, 这 样 的 计 算 机 将 更 加 适
15 C++ 程 序 设 计 面 向 对 象 程 序 设 计 的 特 点 面 向 对 象 程 序 设 计 是 在 吸 取 结 构 化 程 序 设 计 的 一 切 优 点 的 基 础 上 发 展 起 来 的 一 种 全 新 的 程 序 法, 其 本 质 是 把 数 据 和 处 理 数 据 的 过 程 抽 象 成 一 个 具 有 特 定 身 份 和 属 性 的 实 体 对 象 面 程 序 设 计 最 突 出 的 特 点 就 是 封 装 性 继 承 性 和 多 态 性 1. 封 装 性 封 装 是 一 种 数 据 隐 藏 技 术 在 面 向 对 象 程 序 设 计 中 可 以 把 数 据 和 与 数 据 有 关 的 操 作 集 中 在 一 起, 将 类 的 一 部 分 属 性 和 操 作 隐 藏 起 来, 不 让 用 户 访 问 ; 另 一 部 分 作 为 类 的 外 部 接 口, 用 户 可 以 类 通 过 接 口 与 外 部 发 生 联 系, 用 户 只 能 通 过 类 的 外 部 接 口 使 用 类 提 供 的 服 务, 而 内 部 的 具 体 实 则 被 隐 藏 起 来, 对 外 是 不 可 见 的 封 装 可 以 描 述 如 下 1 一 个 清 楚 的 边 界 对 象 的 所 有 属 性 和 操 作 被 限 定 在 该 边 界 内 部 2 一 个 口 该 接 口 用 以 描 述 这 个 对 象 和 其 他 对 象 之 间 的 相 互 作 用, 就 是 给 出 在 编 写 程 序 时, 用 户 可 以 用 的 属 性 和 操 作 3 隐 藏 受 保 护 的 属 性 和 内 部 操 作 类 所 提 供 的 功 能 的 实 现 细 节, 以 及 仅 供 内 和 修 改 的 属 性, 不 能 在 定 义 这 个 对 象 的 类 的 外 部 访 问 C++ 语 言 通 过 类 来 支 持 封 装 性 类 是 对 象 的 抽 象 及 描 述, 对 象 是 类 的 实 例 化 的 产 物, 一 个 类 中 对 象 都 具 有 相 同 的 数 据 结 构 和 操 作 代 码 在 C++ 语 言 中, 类 是 数 据 及 其 相 关 操 作 的 封 装 体, 可 一 个 整 体 来 使 用 类 中 的 具 体 操 作 细 节 被 封 装 起 来, 用 户 在 使 用 一 个 已 定 义 类 的 对 象 时, 无 需 内 部 的 实 际 工 作 流 程, 只 要 知 道 如 何 通 过 其 外 部 接 口 使 用 它 即 可 封 装 的 目 的 就 是 防 止 非 法 访 问 对 属 性 和 操 作 的 访 问 权 限 进 行 合 理 控 制, 减 少 程 序 之 间 的 相 互 影 响, 降 低 出 错 的 可 能 性 2. 继 承 性 继 承 这 一 概 念 在 现 实 世 界 中 无 处 不 在, 如 子 女 会 继 承 父 母 的 大 部 分 特 点, 新 的 产 品 会 在 老 型 号 上 进 行 改 进 因 为 有 继 承, 人 类 的 文 明 史 才 会 不 断 地 延 续 和 发 展 在 面 向 对 象 程 序 设 计 中, 继 承 是 指 新 建 的 类 从 已 有 的 类 那 里 获 得 已 有 的 属 性 和 操 作 已 有 的 类 类 或 父 类, 继 承 基 类 而 产 生 的 新 建 类 称 为 基 类 的 子 类 或 派 生 类 由 父 类 产 生 子 类 的 过 程 称 为 类 C++ 语 言 支 持 单 继 承 和 多 继 承 通 过 继 承, 程 序 可 以 在 现 有 类 的 基 础 上 声 明 新 类, 即 新 类 是 从 的 基 础 上 派 生 出 来 的, 新 类 将 共 享 原 有 类 的 属 性, 并 且 还 可 以 添 加 新 的 属 性 继 承 有 效 地 实 现 代 码 的 重 用, 增 强 了 系 统 的 可 扩 充 性 3. 多 态 性 在 人 们 的 日 常 生 活 中, 常 常 把 下 象 棋 下 跳 棋 下 围 棋 和 下 军 棋 等 统 称 为 下 棋 是 用 下 棋 这 同 一 个 名 称 来 代 替 下 象 棋 下 跳 棋 下 围 棋 和 下 军 棋 等 这 些 类 似 在 面 向 对 象 程 序 设 计 中, 通 过 多 态 性 来 支 持 这 一 思 想 多 态 性 是 指 相 同 的 函 数 名 可 以 有 多 个 不 数 体, 即 一 个 函 数 名 可 以 对 应 多 个 不 同 的 实 现 部 分 在 调 用 同 一 函 数 时, 由 于 环 境 的 不 同, 可 不 同 的 行 为, 导 致 不 同 的 动 作, 这 种 功 能 称 为 多 态 它 使 得 类 中 具 有 相 似 功 能 的 不 同 函 数 可 以 一 个 函 数 名 多 态 既 表 达 了 人 类 的 思 维 方 式, 又 减 少 了 程 序 中 标 示 符 的 个 数, 方 便 了 程 序 员 编 写 程 序 多 态
16 第 1 章 C++ 概 述 7 伴 随 面 向 对 象 程 序 设 计 方 法 的 提 出, 出 现 了 不 少 面 向 对 象 程 序 设 计 语 言 早 在 20 世 纪 60 年 代, 就 了 最 早 的 面 向 对 象 程 序 设 计 语 言 Simula 67 语 言 它 将 Algol 60 语 言 中 的 块 结 构 概 念 向 前 推 进 了 一, 提 出 了 对 象 的 概 念 对 象 代 表 着 待 处 理 问 题 中 的 一 个 实 体, 在 处 理 问 题 过 程 中, 一 个 对 象 可 种 形 式 与 其 他 对 象 通 信 从 概 念 上 讲, 一 个 对 象 是 既 包 含 数 据 又 包 含 有 处 理 这 些 数 据 操 作 的 一 个 程 元 Simula 语 言 中 还 使 用 了 类 的 概 念, 类 是 用 来 描 述 特 性 相 同 或 相 近 的 一 组 对 象 的 结 构 和 行 为 该 也 支 持 类 的 继 承 继 承 可 将 多 个 类 组 成 为 层 次 结 构, 进 而 允 许 共 享 结 构 和 行 为 这 些 概 念 奠 定 了 面 象 程 序 设 计 语 言 的 基 础 20 世 纪 70 年 代 出 现 的 Ada 语 言 是 支 持 数 据 抽 象 类 型 的 最 重 要 的 语 言 之 一 数 据 抽 象 是 一 种 由 数 据 及 作 用 在 数 据 结 构 上 的 操 作 组 成 的 一 个 实 体, 把 数 据 结 构 隐 藏 在 操 作 接 口 的 内 部, 通 过 操 作 接 口 实 部 的 交 流 对 外 部 来 讲, 只 知 道 做 什 么, 而 不 知 道 如 何 做 Ada 语 言 中 面 向 对 象 的 抽 象 结 构 是 包, 持 数 据 抽 象 类 型 函 数 运 算 符 重 载 和 多 态 性 等 面 向 对 象 的 机 制 但 是,Ada 语 言 不 是 全 面 地 支 持, 因 此 人 们 常 称 它 为 基 于 对 象 的 程 序 设 计 语 言 20 世 纪 80 年 代 出 现 的 Smalltalk 语 言 是 最 有 影 响 的 面 向 对 象 程 序 设 计 语 言 之 一, 它 丰 富 了 面 向 对 概 念 该 语 言 并 入 了 Simula 语 言 的 许 多 面 向 对 象 的 特 征, 包 括 类 和 继 承 等, 而 且 信 息 隐 藏 更 加 严 Smalltalk 语 言 是 一 种 弱 类 型 化 的 语 言, 一 个 程 序 中 的 同 一 个 对 象 可 以 在 不 同 时 间 内 表 现 为 不 同 的 自 1986 年 以 来, 面 向 对 象 程 序 设 计 逐 渐 走 出 实 验 室 和 研 究 部 门, 开 始 进 入 实 际 应 用 面 向 对 象 设 计 语 言 大 量 涌 现, 广 泛 地 应 用 于 程 序 设 计, 出 现 了 Object-C,Java 和 C++ 等 有 广 泛 影 响 的 面 向 程 序 设 计 语 言 这 些 语 言 大 致 可 分 为 两 类 (1) 开 发 全 新 的 面 向 对 象 程 序 设 计 语 言, 其 中 最 具 有 代 表 性 的 语 言 是 Java,Smalltalk 和 Eiffel Jav 适 合 网 络 应 用 编 程 ;Smalltalk 语 言 完 整 体 现 了 面 向 对 象 程 序 设 计 的 概 念 ;Eiffel 语 言 除 了 具 有 封 装 和 外, 还 集 成 了 其 他 面 向 对 象 的 特 征, 是 一 种 很 好 的 面 向 对 象 程 序 设 计 语 言 (2) 对 传 统 语 言 进 行 面 向 对 象 程 序 设 计 的 扩 展 这 类 语 言 又 称 混 合 型 语 言, 一 般 是 在 其 他 语 基 础 上 加 入 面 向 对 象 程 序 设 计 的 概 念 开 发 出 来 的, 最 典 型 的 代 表 是 C++ C++ 是 一 种 高 效 实 用 的 型 面 向 对 象 程 序 设 计 语 言, 它 是 在 传 统 C 语 言 的 基 础 上 增 加 了 对 面 向 对 象 程 序 设 计 的 支 持, 包 括 分 : 一 部 分 是 C++ 基 础 部 分, 以 C 语 言 为 核 心 ; 另 一 部 分 是 C++ 面 向 对 象 部 分, 是 C++ 对 C 语 言 充 这 使 得 C++ 既 支 持 传 统 的 面 向 过 程 的 结 构 化 程 序 设 计, 又 支 持 新 型 的 面 向 对 象 程 序 设 计, 同 有 C 语 言 丰 富 的 应 用 基 础 和 开 发 环 境 的 支 持 ; 对 于 已 经 较 好 地 掌 握 了 C 语 言 的 用 户 而 言, 学 习 相 对 容 易 一 些, 这 些 都 是 C++ 成 为 当 前 最 为 流 行 的 面 向 对 象 程 序 设 计 语 言 的 主 要 原 因
17 C++ 程 序 设 计 1.2 C++ 的 发 展 和 特 点 C++ 的 发 展 各 种 程 序 设 计 语 言 对 程 序 设 计 方 法 的 支 持 是 不 同 的,C++ 完 全 支 持 面 向 对 象 程 序 设 计 C++ 的 要 归 功 于 C 语 言,C 语 言 在 C++ 中 作 为 子 集 保 留 了 下 来 C 语 言 是 由 Dennis Ritchie 设 计, 并 在 DEC PDP-11 上 的 Unix 操 作 系 统 环 境 下 实 现 的, 它 是 在 19 Ken Thompson 设 计 的 B 语 言 基 础 上 发 展 来 的 1980 年, 美 国 AT&T 公 司 贝 尔 实 验 室 的 Bjarne Stioustrup 博 士 为 了 仿 真 课 题 研 究, 编 写 了 称 为 C 的 语 言 版 本 1983 年 7 月 用 C++ 将 该 语 言 名 字 定 下 来, 并 向 研 究 小 组 之 外 发 表 C++ 的 名 了 从 C 语 言 而 来 的 演 化 特 性, ++ 是 C 的 增 量 运 算 符, 之 所 以 没 有 叫 D 语 言, 是 因 为 C++ 是 的 扩 充, 它 继 承 了 C 语 言 的 优 点, 又 极 大 地 扩 充 了 C 语 言 的 功 能, 是 在 C 语 言 的 基 础 上 增 加 了 象 程 序 设 计 的 特 征 C++ 已 经 在 众 多 应 用 领 域 中 迅 速 成 为 程 序 员 首 选 的 程 序 设 计 语 言, 尤 其 适 用 于 开 发 大 中 型 项 目 件 开 发 时 间 费 用 到 软 件 的 可 重 用 性 可 扩 充 性 可 维 护 性 以 及 可 靠 性 等 方 面,C++ 都 显 示 出 性 与 之 相 适 应,C++ 语 言 的 开 发 环 境 也 随 之 不 断 推 出 目 前, 常 用 的 C++ 开 发 环 境 主 要 有 Borla +,Visual C++( 简 称 VC) 等 1986 年 Borland 公 司 开 发 了 Turbo C++ 程 序 语 言, 而 后 又 推 出 了 Borland C++ 版 本 Microsoft 公 20 世 纪 80 年 代 中 期 在 Microsoft C 6.0 的 基 础 上 开 发 了 Microsoft C/C++ 7.0, 同 时 引 进 了 Microso ndation Class(MFC)1.0 版 本, 完 善 了 源 代 码 这 些 版 本 都 是 依 赖 于 DOS 环 境 的, 直 到 Microso 推 出 的 Microsoft C/C++ 8.0, 即 Visual C 版 本 出 现, 它 是 第 一 个 真 正 基 于 Windows 环 境 视 化 的 集 成 开 发 环 境, 将 编 辑 编 译 连 接 和 运 行 集 成 为 一 体 从 Visual C 版 本 以 后,Microso 决 定 不 再 将 更 多 的 努 力 花 在 支 持 16 位 编 程 上 虽 然 Visual C 仍 提 供 对 16 位 的 支 持, 但 版 本 以 后,Visual C++ 将 更 多 地 用 来 创 建 32 位 程 序 在 版 本 上,Microsoft 公 司 没 有 推 出 3.0 版 本 号 直 接 从 2.0 跳 到 了 4.0, 将 Visual C++ 与 MFC 的 版 本 号 取 得 一 致 由 于 Internet 的 迅 猛 发 展, 针 对 网 络 环 境 下 的 面 向 对 象 程 序 设 计 明 显 占 据 主 导 地 位, 所 以 Microso 在 Visual C 版 本 中, 引 进 了 为 Internet 编 程 而 设 计 的 新 类 库 Visual C 版 本 也 增 加 新 类, 但 注 意 力 更 多 地 集 中 在 改 善 界 面 设 计 上, 以 提 供 一 个 更 好 的 在 线 帮 助 系 统 更 高 级 的 宏 对 在 开 发 者 组 内 进 行 类 和 其 他 代 码 共 享 的 支 持 伴 随 Windows 98 操 作 系 统 的 发 布,Microsoft 公 司 又 隆 重 推 出 了 Visual C 它 在 Visual C++ 5 础 上 做 了 很 大 改 进, 提 供 了 许 多 新 的 特 点, 功 能 更 加 强 大 它 具 有 以 下 特 点 (1) 编 译 器 较 以 前 有 了 很 大 的 改 进, 可 以 支 持 ANSI C++ 标 准, 并 支 持 布 尔 类 型, 对 于 模 板 的 得 到 了 改 善 (2)Visual C 开 发 环 境 Developer Studio 是 由 Windows 95/98 或 Windows NT 环 境 下 运 行 集 成 工 具 所 组 成 Developer Studio 编 辑 器 有 了 很 大 的 改 善, 它 具 有 允 许 编 辑 器 自 动 地 完 成 通 用 辑 的 特 点 使 用 Developer Studio 不 仅 可 以 创 建 被 Visual C 使 用 的 源 文 件 和 其 他 文 档, 而
18 第 1 章 C++ 概 述 9 作 区 窗 口 来 查 看 和 访 问 项 目 中 的 各 种 元 素 (3)Visual C 包 括 一 些 增 加 的 MFC(Microsoft Fundation Class) 库 的 新 功 能 增 加 的 内 容 包 Internet 编 程 的 库 和 支 持 在 Internet Explorer 和 Windows 98 中 介 绍 的 新 的 通 用 控 件 (4)Visual C 提 供 了 最 快 的 集 成 数 据 库 访 问 方 式, 允 许 用 户 建 立 强 有 力 的 数 据 库 应 用 程 序 使 用 ODBC 类 和 高 性 能 的 32 位 ODBC 驱 动 程 序 来 访 问 各 种 数 据 库 管 理 系 统, 也 可 以 使 用 DA 据 访 问 对 象 ) 类 通 过 编 程 语 言 来 访 问 和 操 纵 数 据 库 中 的 数 据 并 管 理 数 据 库 数 据 库 对 象 与 结 构 (5)Visual C 对 Internet 提 供 了 强 有 力 的 支 持 (6) 一 个 增 强 型 的 联 机 帮 助 系 统 使 Visual C 变 得 容 易 学 习, 只 需 单 击 鼠 标 即 可 实 现 若 机 上 安 装 了 MSDN, 联 机 帮 助 系 统 将 自 动 使 用 最 新 的 MSDN 版 本 总 之,Visual C++ 经 历 了 从 1.0 到 6.0 版 本 的 发 展, 软 件 系 统 逐 渐 庞 大, 功 能 也 日 臻 完 善 考 虑 ual C 的 流 行 性, 本 书 将 以 Visual C 作 为 编 写 C++ 程 序 的 集 成 开 发 环 境, 所 有 程 序 均 中 文 VC 集 成 开 发 环 境 下 运 行 通 过 C++ 的 特 点 (1)C++ 全 面 兼 容 C 语 言, 许 多 C 语 言 代 码 不 经 修 改 就 可 以 在 C++ 中 使 用 (2) 用 C++ 编 写 的 程 序 可 读 性 更 好, 代 码 结 构 更 为 合 理 (3) 生 成 代 码 质 量 高, 运 行 效 率 仅 比 汇 编 语 言 慢 10%~20% (4) 从 开 发 时 间 费 用 到 形 成 软 件 的 可 重 用 性 可 扩 充 性 可 维 护 性 和 可 靠 性 等 方 面 都 有 很 大 使 得 大 中 型 软 件 开 发 变 得 容 易 (5) 支 持 面 向 对 象 程 序 设 计, 可 方 便 地 构 造 出 模 拟 现 实 问 题 的 实 体 和 操 作 C++ 与 C 语 言 的 关 系 C++ 是 C 语 言 的 一 个 超 集,C++ 包 含 了 C 语 言 的 全 部 内 容, 它 与 C 语 言 的 关 系 如 下 1.C++ 保 持 了 与 C 语 言 的 兼 容 这 种 兼 容 性 表 现 在 绝 大 多 数 C 语 言 程 序 代 码 无 需 任 何 修 改 就 可 以 直 接 在 C++ 程 序 中 应 用, 用 C 写 的 许 多 库 函 数 和 应 用 软 件 也 都 可 以 直 接 用 于 C++, 这 使 得 C 程 序 员 能 够 更 容 易 地 学 习 C++, 握 C++ 语 言 的 新 特 征 就 可 以 了 但 是, 这 种 兼 容 性 也 使 得 C++ 语 言 不 是 一 个 纯 粹 的 面 向 对 象 程 序 设 计 语 言 因 为 C 语 言 是 面 向 过 序 设 计 语 言,C++ 要 与 C 语 言 兼 容, 所 以 C++ 也 要 支 持 面 向 过 程 的 程 序 设 计 这 使 得 C++ 可 以 将 同 风 格 的 程 序 设 计 技 术 融 为 一 体, 但 也 有 可 能 使 初 学 者 感 到 无 所 适 从 因 此, 在 学 习 C++ 程 序 设 计 时 用 面 向 过 程 的 思 想 去 学 习 面 向 对 象 的 程 序 设 计, 要 转 变 以 前 传 统 的 观 念, 注 意 采 用 面 向 对 象 的 思 维 从 全 新 的 面 向 对 象 的 角 度 来 学 习 C++ 程 序 设 计 2.C++ 对 C 语 言 作 了 很 多 改 进 C++ 既 保 持 了 C 语 言 的 简 洁 高 效 的 特 点, 同 时 又 对 C 语 言 作 了 改 进 和 补 充, 主 要 有 以 下 几 点 (1) 增 加 了 一 些 新 的 运 算 符, 使 得 C++ 应 用 起 来 更 加 方 便 例 如 :::,new,delete 和 > 等 (2) 改 进 了 类 型 系 统, 增 加 了 安 全 性 C 语 言 中 类 型 转 换 很 不 严 格,C++ 规 定 类 型 转 换 多 采 取 换 ; 又 规 定 函 数 的 说 明 必 须 采 用 原 型 ; 对 缺 省 类 型 作 了 些 限 制 ; 还 增 加 了 编 译 系 统 检 查 类 型 的
19 C++ 程 序 设 计 (4) 允 许 函 数 和 运 算 符 重 载, 允 许 设 置 缺 省 参 数, 这 些 措 施 提 供 了 程 序 的 灵 活 性, 减 少 了 冗 余 性 进 了 内 联 函 数 的 概 念, 提 高 了 程 序 的 效 率 (5) 对 变 量 说 明 更 加 灵 活 C 语 言 只 允 许 在 函 数 体 内 部 进 行 说 明, 而 且 必 须 先 声 明 后 使 用, 否 出 错 C++ 打 破 了 这 一 限 制, 可 以 根 据 需 要 随 时 对 变 量 进 行 说 明 3.C++ 与 C 语 言 的 本 质 区 别 C 语 言 仅 仅 支 持 面 向 过 程 的 程 序 设 计, 而 C++ 是 在 C 语 言 的 基 础 上 增 加 了 面 向 对 象 程 序 设 计 的, 所 以 C++ 支 持 面 向 对 象 程 序 设 计 可 以 说 C++ 不 仅 仅 是 对 C 语 言 进 行 了 一 些 改 进, 更 重 要 的 了 一 次 变 革, 使 得 C++ 成 为 学 习 面 向 对 象 程 序 设 计 的 首 选 1.3 C++ 程 序 基 本 结 构 学 习 C++ 程 序 设 计, 最 好 先 从 最 简 单 的 C++ 程 序 开 始, 先 接 触 C++ 的 最 基 本 结 构, 以 后 再 逐 步 了 解 C++ 程 序 的 完 整 结 构 C++ 程 序 基 本 结 构 现 在 通 过 编 制 一 个 小 程 序 来 说 明 C++ 程 序 的 基 本 结 构, 该 程 序 在 屏 幕 上 显 示 输 出 一 行 字 符 串 Th y first C++ program! 例 1.1 一 个 简 单 的 C++ 程 序 # include "iostream.h" void main() // 在 显 示 器 上 输 出 显 示 一 行 字 符 串 cout<<"this is my first C++ program! "<<endl; 下 面 来 分 析 例 1.1 的 程 序 结 构 程 序 第 一 行 #include <iostream.h> 是 一 条 预 处 理 指 令, 指 示 编 译 器 将 头 文 件 iostream.h 中 的 代 码 程 序 中 该 指 令 所 在 之 处 C++ 程 序 开 始 部 分 出 现 以 # 开 头 的 命 令, 表 示 这 些 命 令 是 预 处 理 命 令 C+ 了 3 类 预 处 理 命 令 : 宏 定 义 命 令 文 件 包 含 命 令 和 条 件 编 译 命 令 例 1.1 中 出 现 的 # inclu stream.h> 是 文 件 包 含 命 令, 其 中 include 是 关 键 字, 尖 括 号 内 是 被 包 含 的 文 件 名,iostream.h 是 一 件, 它 以.h 为 扩 展 名, 该 文 件 包 含 程 序 输 入 / 输 出 操 作 所 必 须 的 标 准 输 入 / 输 出 流 对 象 第 二 行 定 义 了 一 个 主 函 数 main(), 其 中 main 是 函 数 名,void 表 示 该 函 数 没 有 返 回 值 它 是 程 执 行 的 地 方, 即 程 序 生 成 可 执 行 文 件 后, 将 在 此 处 开 始 运 行 程 序 C++ 的 程 序 是 由 若 干 个 文 件, 每 个 文 件 又 由 若 干 个 函 数 组 成 因 此, 可 以 认 为 C++ 的 程 序 就 是 由 一 个 个 的 函 数 组 成 的 函 是 相 互 独 立 的, 相 互 之 间 可 以 调 用 在 组 成 一 个 C++ 程 序 的 若 干 个 函 数 中, 必 须 有 一 个 且 只 能 主 函 数 main() 执 行 程 序 时, 系 统 先 从 主 函 数 开 始 运 行, 其 他 函 数 只 能 被 主 函 数 调 用 或 通 过 主 用 的 函 数 所 调 用, 函 数 可 以 嵌 套 调 用, 即 在 一 个 函 数 中 调 用 另 外 一 个 函 数 主 函 数 可 以 带 参 数 以 不 带 参 数 函 数 在 调 用 之 前, 必 须 先 定 义 好 定 义 函 数 要 按 照 系 统 规 定 的 格 式 进 行, 以 后 再
20 第 1 章 C++ 概 述 11 函 数 的 结 束 函 数 体 部 分 由 许 多 C++ 语 句 组 成, 这 些 语 句 描 述 了 函 数 的 功 能 实 现 第 四 行 是 程 序 的 注 释 部 分, 用 来 说 明 下 面 的 语 句 是 要 在 显 示 器 上 输 出 显 示 一 行 字 符 串 注 释 信 较 大 或 较 复 杂 的 C++ 程 序 是 非 常 必 要 的, 可 以 解 释 一 行 语 句 或 几 行 语 句 的 作 用 或 功 能, 提 高 程 读 性 在 C++ 中, 注 释 信 息 有 两 种 类 型 : 一 种 是 如 例 1.1 所 示 用 // 作 注 释, 则 本 行 中 // 字 符 都 会 被 作 为 注 释 信 息 处 理 ; 另 一 种 注 释 信 息 是 用 /* 和 */ 作 注 释, 则 /* 和 */ 所 有 字 符 都 会 被 作 为 注 释 信 息 处 理, 此 时 的 注 释 信 息 可 以 是 一 行, 也 可 以 是 多 行, 适 合 于 大 块 第 五 行 是 主 函 数 的 函 数 体 部 分, 也 是 例 1.1 的 主 要 部 分 该 部 分 只 有 一 条 语 句, 其 中 cout 是 标 流 对 象, 实 际 指 定 显 示 器 为 输 出 设 备 ; << 是 cout 中 的 运 算 符, 表 示 把 它 后 面 的 数 据 在 输 出 输 出 显 示 ; This is my first C++ program! 是 要 输 出 显 示 的 具 体 内 容, 双 引 号 表 示 要 显 示 是 一 个 字 符 串 ; 最 后 的 endl 表 示 回 车 换 行 ; 分 号 ; 表 示 语 句 结 束,C++ 规 定 语 句 必 须 要 用 ; 结 尾 由 以 上 分 析 可 以 看 出, 一 个 C++ 程 序 的 基 本 结 构 包 括 以 # 开 头 的 若 干 个 预 处 理 命 令, 将 程 要 的 头 文 件 包 含 进 来 ; 然 后 是 定 义 主 函 数 和 其 他 函 数, 当 然 函 数 也 可 以 在 程 序 的 起 始 部 分 先 利 原 型 进 行 声 明, 在 以 后 再 进 行 定 义 ; 用 大 括 号 括 起 来 的 部 分 就 是 函 数 体 部 分, 函 数 体 部 分 主 各 种 各 样 的 语 句 和 注 释 信 息, 这 部 分 应 该 是 程 序 的 主 体 部 分, 占 的 比 重 也 最 大 C++ 程 序 的 书 写 格 式 C++ 程 序 的 书 写 格 式 基 本 与 C 语 言 程 序 书 写 格 式 相 同 基 本 原 则 如 下 (1) 一 般 情 况 下 一 行 只 写 一 条 语 句 短 语 句 可 以 一 行 写 多 条, 长 语 句 可 以 分 成 多 行 来 写 分 行 不 能 将 一 个 单 词 分 开 ; 用 双 引 号 括 起 来 的 字 符 串 最 好 也 不 要 分 开, 如 果 一 定 要 分 开, 有 的 编 译 求 在 行 尾 加 上 续 行 符 \ (2)C++ 程 序 书 写 时 要 尽 量 提 高 可 读 性 因 此, 采 用 适 当 地 缩 进 格 式 书 写 程 序 是 非 常 必 要 的, 类 内 容 或 同 一 层 次 的 语 句 要 对 齐 例 如, 一 个 循 环 的 循 环 体 中 的 各 语 句 要 对 齐, 同 一 个 if 语 句 if 体 内 的 若 干 条 语 句 或 else 体 内 的 若 干 语 句 要 对 齐 (3)C++ 程 序 中 大 括 号 使 用 较 多, 其 书 写 方 法 也 较 多, 建 议 用 户 要 养 成 使 用 大 括 号 的 固 定 例 如, 每 个 大 括 号 占 一 行, 并 与 使 用 大 括 号 的 语 句 对 齐, 大 括 号 内 的 语 句 采 用 缩 进 两 个 字 符 的 写, 如 例 1.1 所 示 1.4 C++ 程 序 的 上 机 实 现 C++ 源 程 序 要 经 过 编 辑 编 译 连 接 和 运 行 4 个 环 节, 才 能 在 屏 幕 上 显 示 结 果 例 如, 要 编 制 为 Hello 的 程 序, 其 操 作 流 程 如 图 1-1 所 示 源 程 序 目 标 程 序 可 执 行 程 序 编 辑 编 译 连 接 运 行 Hello.cpp Hello.obj Hello.exe
21 C++ 程 序 设 计 编 辑 编 辑 是 将 写 好 的 C++ 源 程 序 输 入 到 计 算 机 中 生 成 磁 盘 文 件 的 过 程 C++ 程 序 的 编 辑 可 以 使 用 计 提 供 的 各 种 编 辑 器 进 行 编 辑, 编 辑 好 的 源 程 序 可 以 保 存 到 磁 盘 文 件 中, 默 认 文 件 扩 展 名 为 *.cpp Visual C 为 编 辑 C++ 源 程 序 提 供 了 一 个 功 能 良 好 的 编 辑 器, 其 主 要 编 辑 功 能 有 定 义 块 移 复 制 块 删 除 块 插 入 字 符 以 及 保 存 文 件 等 编 译 编 辑 好 的 源 程 序 必 须 经 过 编 译, 翻 译 成 计 算 机 能 够 识 别 的 机 器 代 码, 计 算 机 才 能 执 行 编 译 器 C++ 源 程 序 转 换 成 二 进 制 代 码 的 形 式, 这 些 二 进 制 代 码 称 为 目 标 代 码 将 这 些 目 标 代 码 以 *.obj 为 保 存 在 磁 盘 中, 称 为 目 标 程 序 编 译 阶 段 要 进 行 词 法 分 析 和 语 法 分 析, 又 称 源 程 序 分 析 这 一 阶 段 主 要 是 分 析 程 序 的 语 法 结 构 C++ 源 程 序 的 语 法 错 误 如 果 分 析 过 程 中 发 现 有 不 符 合 要 求 的 语 法 错 误, 就 会 及 时 报 告 给 用 户, 类 型 显 示 在 屏 幕 上 例 如, 在 程 序 中 将 标 准 输 出 流 对 象 cout 误 写 成 couth, 则 进 行 编 译 时, 在 信 窗 口 会 显 示 error C2065: couth :undeclared identifier, 表 明 couth 是 一 个 没 有 声 明 的 标 识 符 该 错 误 信 息, 光 标 会 指 到 出 错 的 代 码 行, 便 于 用 户 进 行 修 改 编 译 可 以 生 成 符 号 表 或 称 数 据 字 典, 它 用 来 映 射 程 序 中 的 各 种 符 号 及 它 们 的 属 性, 如 某 个 变 量 所 占 内 存 空 间 和 分 配 在 存 储 器 中 的 相 对 位 置 等 连 接 编 译 后 生 成 的 目 标 代 码 还 不 能 直 接 在 计 算 机 上 运 行, 其 主 要 原 因 是 编 译 器 对 每 个 源 程 序 文 件 分 别 进 行 如 果 一 个 程 序 有 多 个 源 程 序 文 件, 编 译 后 这 些 源 程 序 文 件 还 分 布 在 不 同 的 地 方 因 此, 需 要 把 它 们 连 起, 生 成 可 以 在 计 算 机 上 运 行 的 可 执 行 文 件 即 使 C++ 源 程 序 只 有 一 个 源 文 件, 这 个 源 文 件 生 成 的 目 还 需 要 系 统 提 供 的 库 文 件 中 的 一 些 代 码, 故 也 需 要 连 接 起 来 连 接 工 作 一 般 由 编 译 系 统 中 的 连 接 程 序 ( 又 称 连 接 器 ) 来 完 成, 连 接 器 将 由 编 译 器 生 成 的 目 标 件 和 库 中 的 某 些 文 件 连 接 在 一 起, 生 成 一 个 可 执 行 文 件 可 执 行 文 件 的 默 认 扩 展 名 为 *.exe 运 行 一 个 C++ 源 程 序 经 过 编 译 和 连 接 后 生 成 了 可 执 行 文 件, 该 文 件 可 以 在 Windows 环 境 下 直 接 双 击 也 可 以 在 Visual C 的 集 成 开 发 环 境 下 运 行 程 序 运 行 后, 将 在 屏 幕 上 显 示 运 行 结 果 或 显 示 提 示 用 户 输 入 数 据 的 信 息 用 户 可 以 根 据 运 行 结 断 程 序 是 否 有 算 法 错 误 在 生 成 可 执 行 文 件 之 前, 一 定 要 改 正 编 译 和 连 接 时 出 现 的 致 命 错 误 和 误, 这 样 才 能 保 证 运 行 结 果 是 正 确 的 因 为 程 序 中 的 警 告 错 误 虽 然 不 影 响 生 成 可 执 行 文 件, 但 导 致 结 果 错 误 下 面 以 一 个 简 单 C++ 程 序 设 计 为 例 来 说 明 C++ 程 序 的 上 机 实 现 过 程 (1) 启 动 Visual C 用 户 可 以 单 击 开 始 菜 单, 在 程 序 选 项 中 选 择 Microsoft Visu dio 6.0 级 联 菜 单 下 的 Microsoft Visual C++6.0, 或 在 桌 面 上 双 击 Microsoft Visual C++6.0
22 第 1 章 C++ 概 述 13 图 1-2 Visual C++ 的 集 成 开 发 环 境 (2) 在 文 件 菜 单 下, 选 择 新 建 命 令, 将 弹 出 新 建 对 话 框, 如 图 1-3 所 示 图 1-3 新 建 对 话 框 在 该 对 话 框 中 选 择 工 程 标 签 下 的 Win32 Console Application 选 项, 可 创 建 一 个 基 于 控 制 程 序 的 工 程 在 工 程 编 辑 栏 内 输 入 创 建 的 工 程 名 称 (sum), 在 位 置 编 辑 栏 内 输 入 工 程 位 置 (f:\sum), 其 他 选 项 选 择 默 认 值, 单 击 确 定 按 钮 将 弹 出 Win32 Console Application 骤 对 话 框, 如 图 1-4 所 示
23 C++ 程 序 设 计 图 1-4 Win32 Console Application 项 目 步 骤 对 话 框 (3) 在 Win32 Console Application 项 目 步 骤 对 话 框 中, 用 户 可 以 选 择 想 要 创 建 应 用 程 序 的 类 型 4 个 选 项 : 一 个 空 白 工 程 一 个 简 单 应 用 程 一 个 世 界, 你 好 应 用 程 序 和 一 个 支 持 C 的 应 用 程 序 不 同 的 选 项 意 味 着 系 统 自 动 生 成 码 会 有 所 不 同 此 例 中 选 择 第 2 个 选 项, 创 建 一 个 简 单 的 应 用 然 后 单 击 完 成 按 钮, 将 出 现 新 建 工 程 对 话 框 如 图 1-5 所 示 该 对 话 框 给 出 了 新 创 程 的 简 单 信 息 (4) 单 击 确 定 按 钮, 将 回 到 Visual C 成 开 发 环 境 至 此, 一 个 新 的 应 用 程 序 创 建 完 成, 系 统 为 用 户 创 建 了 主 文 件 sum.cpp 和 预 编 译 头 文 件 Stdafx.h, 1-6 所 示 在 右 边 的 程 序 编 辑 窗 口 中 输 入 以 下 代 码 : #include"iostream.h" // 函 数 原 型 int add(int a,int b); 图 1-5 新 建 工 程 信 息 对 话 框
24 第 1 章 C++ 概 述 15 图 1-6 新 创 建 的 应 用 程 序 int main(int argc, char* argv[]) int x,y,sum; cout<<" 请 输 入 两 个 整 数 :"<<endl; cin>>x>>y; sum=add(x,y); cout<<" 两 数 之 和 为 :"<<sum<<endl; return 0; // 函 数 add 定 义 int add(int a,int b) int c; c=a+b; return c; 代 码 输 入 完 毕 后, 单 击 文 件 菜 单 中 的 保 存 命 令, 或 直 接 单 击 工 具 栏 上 的 保 存 工 具 保 存 C++ 源 程 序, 文 件 名 为 sum.cpp (5) 用 户 也 可 以 在 新 建 对 话 框 中 选 择 文 件 标 签, 出 现 如 图 1-7 所 示 的 界 面 在 该 对 话
25 可 进 入 代 码 编 辑 窗 口, 如 图 1-8 所 示 C++ 程 序 设 计 图 1-7 新 建 文 件 对 话 框 图 1-8 代 码 编 辑 窗 口 在 该 窗 口 中 输 入 程 序 代 码 (6) 单 击 微 型 编 译 工 具 栏 中 的 编 译 程 序 工 具 按 钮, 对 C++ 源 程 序 sum.cpp 进 行 编 译 如 有 错 误, 需 要 回 到 程 序 编 辑 窗 口 重 新 编 辑, 直 到 没 有 错 误 为 止 此 时, 将 在 信 息 输 出 窗 口 中 显 m.obj - 0 error(s), 0 warning(s) 的 信 息 (7) 编 译 完 成 后, 单 击 微 型 编 译 工 具 栏 中 的 连 接 程 序 工 具 按 钮, 如 果 没 有 连 接 错 误, 将 执 行 文 件 sum.exe
26 第 1 章 C++ 概 述 17 图 1-9 程 序 执 行 结 果 程 序 运 行 后, 将 弹 出 一 个 窗 体 要 求 用 户 输 入 两 个 整 数, 用 户 输 入 两 个 整 数 ( 如 4 和 5) 后 回 车, 显 示 求 和 的 结 果, 如 图 1-9 所 示 习 题 1. 试 比 较 面 向 对 象 程 序 设 计 结 构 化 程 序 设 计 和 模 块 化 程 序 设 计 2. 解 释 以 下 概 念 : 类 对 象 封 装 数 据 抽 象 继 承 多 态 3. 谈 谈 你 对 C++ 语 言 特 点 的 理 解 4. 编 写 程 序 在 屏 幕 上 显 示 字 符 串 欢 迎 大 家 学 习 C++ 语 言!, 并 按 照 书 中 介 绍 练 习 C++ 语 言 实 现 过 程
27 第 2 章 基 本 数 据 类 型 和 表 达 式 数 据 是 程 序 处 理 的 对 象, 是 程 序 中 必 不 可 少 的 重 要 组 成 部 分 对 不 同 类 型 的 数 据 有 不 同 的 处 理 方 法, 每 种 数 据 都 有 适 合 自 己 运 算 规 则 的 表 达 式 C++ 语 言 提 供 了 丰 富 的 数 据 类 型 运 算 符 和 表 达 式, 能 够 准 确 地 描 述 现 实 世 界 的 各 种 问 题, 方 便 有 效 地 加 工 处 理 各 种 类 型 的 数 据 2.1 词 法 符 号 就 像 一 篇 英 语 文 章 是 由 英 文 单 词 和 标 点 符 号 组 成, 而 单 词 是 由 26 个 英 文 字 母 组 成 一 样, 一 个 由 特 定 程 序 设 计 语 言 编 写 的 程 序 也 有 一 些 确 定 的 单 词 和 字 符 可 以 使 用 单 词 又 称 词 法 符 号, 它 是 由 若 干 个 字 符 组 成 的 具 有 一 定 意 义 的 最 小 词 法 单 元 C++ 语 言 中 共 有 5 种 词 法 符 号 : 标 识 符 关 键 字 常 量 运 算 符 和 分 隔 符 在 介 绍 词 法 符 号 之 前, 先 来 了 解 C++ 语 言 可 以 使 用 的 字 符 集 字 符 是 构 成 C++ 语 言 的 基 本 要 素, 所 有 可 用 的 字 符 构 成 了 字 符 集, 就 像 英 语 中 的 26 个 英 文 字 母 和 各 种 可 用 的 标 点 符 号 一 样 C++ 语 言 的 字 符 集 包 括 以 下 几 种 (1) 英 文 字 母 :A~Z,a~z (2) 数 字 字 符 :0~9 (3) 特 殊 字 符 : 空 格! # % ^ & * _( 下 划 线 ) + = ~ < > / \ ' " ;., ( ) [] 标 识 符 标 识 符 是 程 序 员 为 命 名 程 序 中 的 一 些 实 体 而 定 义 的 专 用 词 法 符 号, 常 见 的 有 函 数 名 类 名 变 量 名 常 量 名 和 对 象 名 等 C++ 语 言 中 标 识 符 的 命 名 规 则 如 下 (1) 标 识 符 由 英 文 字 母 ( 包 括 大 写 和 小 写 ) 数 字 和 下 划 线 组 成, 并 且 以 字 母 和 下 划 线 开 始, 其 后 跟 零 个 或 多 个 字 母 数 字 或 下 划 线 注 意 : 标 识 符 不 可 以 数 字 开 始 例 如,Abc,X1,_x1 及 desk 都 是 合 法 的 标 识 符, 而 2A 是 非 法 的 (2) 标 识 符 中 大 写 和 小 写 字 母 是 有 区 别 的 例 如,A1 和 a1 是 两 个 不 同 的 标 识 符 (3) 标 识 符 的 长 度 是 任 意 的, 但 有 的 编 译 系 统 仅 识 别 前 32 个 字 符 (4) 标 识 符 不 能 和 C++ 语 言 的 关 键 字 同 名 关 键 字 关 键 字 是 一 种 有 特 殊 用 途 的 词 法 符 号, 是 C++ 系 统 预 定 义 的 保 留 字, 不 能 再 用 作 其 他 用 途
28 第 2 章 基 本 数 据 类 型 和 表 达 式 19 下 面 列 举 一 些 C++ 语 言 中 常 用 的 关 键 字 auto break bool case char class const continue default delete do double else enum explicit extern float for friend goto if inline int long mutable new operator private protected public register return short signed sizeof static static_cast struct switch this true typedef union unsigned using virtual void while 常 量 常 量 在 运 算 过 程 中 值 保 持 不 变, 可 以 直 接 用 字 符 表 示 常 量 包 括 数 字 常 量 字 符 常 量 和 字 符 串 常 量 例 如, 定 义 常 量 pi 表 示 圆 周 率 , 则 以 后 就 可 以 用 pi 替 代 运 算 符 运 算 符 是 C++ 语 言 实 现 各 种 运 算 的 符 号, 包 括 +,,* 和 / 等 运 算 符 根 据 操 作 对 象 的 个 数 不 同, 可 以 分 为 单 目 运 算 符 双 目 运 算 符 和 三 目 运 算 符 单 目 运 算 符 又 称 一 元 运 算 符, 它 只 对 一 个 操 作 数 进 行 操 作 例 如, 求 负 运 算 符 (-) 逻 辑 求 反 运 算 符 (!) 等 双 目 运 算 符 又 称 二 元 运 算 符, 它 可 以 对 两 个 操 作 数 进 行 操 作 例 如, 加 法 运 算 符 (+) 乘 法 运 算 符 (*) 等 三 目 运 算 符 又 称 三 元 运 算 符, 它 可 以 对 三 个 操 作 数 进 行 操 作 C++ 语 言 中 只 有 一 个 三 目 运 算 符, 就 是 条 件 运 算 符 (?:) 有 关 各 种 运 算 符 的 使 用 方 法 将 在 以 后 的 章 节 中 详 细 介 绍 分 隔 符 分 隔 符 又 称 标 点 符 号, 是 用 来 分 隔 单 词 或 程 序 正 文 的, 它 可 以 表 示 某 个 程 序 实 体 的 结 束 和 另 一 个 程 序 实 体 的 开 始 在 C++ 语 言 中, 常 用 的 分 隔 符 有 以 下 几 个 (1) 空 格 符 : 常 用 来 作 为 单 词 与 单 词 之 间 的 分 隔 符 (2) 逗 号 : 用 来 作 为 多 个 变 量 之 间 的 分 隔 符, 或 用 来 作 为 函 数 的 多 个 参 数 之 间 的 分 隔 符 (3) 分 号 : 仅 用 来 作 为 for 循 环 语 句 中 for 关 键 字 后 面 括 号 中 三 个 表 达 式 的 分 隔 符 (4) 冒 号 : 用 来 作 为 语 句 标 号 与 语 句 之 间 的 分 隔 符, 或 switch 语 句 中 关 键 字 case< 整 型 常 量 > 与 语 句 序 列 之 间 的 分 隔 符 还 有 () 和 也 可 以 作 为 分 隔 符 这 些 分 隔 符 不 表 示 任 何 实 际 的 操 作, 仅 用 于 构 造 程 序 由 于 C++ 编 译 器 将 注 释 也 当 作 空 白 对 待, 故 注 释 也 可 用 作 分 隔 符 2.2 基 本 数 据 类 型 C++ 语 言 中, 程 序 能 够 处 理 的 所 有 数 据 肯 定 都 属 于 某 种 数 据 类 型 数 据 类 型 不 同, 则 数 据 所 占 用 的 存 储 空 间, 所 能 表 示 的 数 据 范 围 和 精 度 以 及 所 能 进 行 的 运 算 均 不 相 同 C++ 语 言 的 数 据 类 型 是 十 分 丰 富 的, 大 致 可 分 为 基 本 数 据 类 型 和 非 基 本 数 据 类 型 基 本
29 20 C++ 程 序 设 计 数 据 类 型 包 括 整 型 字 符 型 浮 点 型 和 布 尔 型 非 基 本 数 据 类 型 主 要 包 括 数 组 类 型 结 构 体 类 型 共 用 体 类 型 指 针 类 型 和 空 类 型 等, 如 图 2-1 所 示 本 章 将 主 要 讨 论 基 本 数 据 类 型, 非 基 本 数 据 类 型 的 有 关 知 识 将 在 以 整 型 字 符 型 基 本 整 型 短 整 型 长 整 型 后 的 章 节 介 绍 除 了 如 图 2-1 所 示 的 数 据 类 型 以 外,C++ 还 提 供 了 4 个 类 型 修 饰 符 作 为 前 缀, 它 用 来 基 本 数 据 类 型 单 精 度 型 浮 点 型 双 精 度 型 布 尔 型 改 变 基 本 数 据 类 型 的 含 义, 以 便 更 准 确 地 适 应 各 种 情 况 的 需 要 这 4 个 类 型 修 饰 符 分 别 是 :long 长 型,signed 有 符 号,unsigned 无 符 号,short 短 型 其 中 long 和 short 在 修 饰 基 本 整 型 int 时 可 省 略 int,signed 在 表 示 有 符 号 数 时 可 省 略 signed 数 据 类 型 决 定 了 数 据 在 内 存 中 所 占 的 空 数 组 类 型 数 据 类 型 构 造 数 据 类 型 结 构 体 类 型 共 用 体 类 型 指 针 类 型 空 类 型 图 2-1 C++ 语 言 的 数 据 类 型 间 大 小, 也 确 定 了 表 示 范 围 各 种 基 本 数 据 类 型 的 长 度 和 取 值 范 围 如 表 2-1 所 示 表 2-1 C++ 的 基 本 数 据 类 型 数 据 类 型 说 明 长 度 ( 字 节 ) 取 值 范 围 bool 布 尔 型 true,false char(signed char) 字 符 型 1 128~127 unsigned char 无 符 号 字 符 型 1 0~255 short(signed short) 短 整 型 ~32767 unsigned short 无 符 号 短 整 型 2 0~65535 int(signed int) 基 本 整 型 ~ unsigned int 无 符 号 整 型 4 0~ long(signed long) 长 整 型 ~ unsigned long 无 符 号 长 整 型 4 0~ float 单 精 度 型 ~ double 双 精 度 型 ~ 说 明 : (1) 单 精 度 型 float 和 双 精 度 型 double 都 属 于 浮 点 型 (2)char 型 和 各 种 int 型 有 时 又 统 称 为 整 数 类 型 因 为 字 符 型 数 据 在 计 算 机 中 是 以 ASCII 码 形 式 表 示, 故 其 本 质 上 是 整 数 类 型 的 一 部 分, 也 可 以 当 作 整 数 来 运 算 (3) 各 种 数 据 类 型 的 长 度 以 字 节 为 单 位,1 个 字 节 等 于 8 个 二 进 制 位 数 2.3 常 量 与 变 量 在 程 序 运 行 过 程 中, 值 不 能 被 改 变 的 量 称 为 常 量, 值 可 以 改 变 的 量 称 为 变 量 在 C++ 程 序 中, 数 据 以 常 量 或 变 量 的 形 式 来 表 示, 每 个 常 量 或 变 量 都 有 确 定 的 数 据 类 型
30 第 2 章 基 本 数 据 类 型 和 表 达 式 常 量 1. 整 型 常 量 整 型 常 量 即 整 型 常 数, 没 有 小 数 部 分, 可 以 用 十 进 制 八 进 制 和 十 六 进 制 3 种 形 式 来 表 示 (1) 十 进 制 整 型 常 量 由 0~9 组 成, 没 有 前 缀, 不 能 以 0 开 始 例 如,234, 67 为 合 法 的 十 进 制 整 型 常 量 (2) 八 进 制 整 型 常 量 以 0 为 前 缀, 后 跟 由 0~7 组 成 的 整 型 常 数 例 如,0134, 076 为 合 法 的 八 进 制 整 型 常 量 (3) 十 六 进 制 整 型 常 量 以 0X 或 0x 为 前 缀, 后 跟 由 0~9 和 A~F 组 成 的 整 型 常 数 例 如, 0x2F,0xA3B4 为 合 法 的 十 六 进 制 整 型 常 量 整 型 常 量 中 的 长 整 型 用 L 或 l 作 后 缀 表 示 例 如,324L,076L 等 整 型 常 量 中 的 无 符 号 型 用 U 或 u 作 后 缀 表 示 例 如,431U,0x34DU 等 2. 浮 点 型 常 量 浮 点 型 常 量 又 称 实 型 常 量, 是 由 整 数 部 分 和 小 数 部 分 组 成 的, 只 能 用 十 进 制 表 示 浮 点 型 常 量 有 两 种 表 示 方 法 : 小 数 表 示 法 和 科 学 计 数 法 (1) 小 数 表 示 法 : 由 符 号 数 字 和 小 数 点 组 成 例 如,9.55,.25,4. 和 等 注 意 : 必 须 有 小 数 点 (2) 科 学 计 数 法 : 是 用 指 数 形 式 来 表 示 浮 点 型 常 量, 即 在 小 数 表 示 法 后 面 加 上 E 或 e 表 示 指 数 例 如,3.2E 5,7e10, 34.5e2 等 注 意 :E 或 e 的 前 面 必 须 要 有 数 字, 指 数 部 分 可 正 可 负, 但 必 须 是 整 数 3. 字 符 常 量 C++ 中 有 两 种 字 符 常 量, 即 一 般 字 符 常 量 和 转 义 字 符 常 量 (1) 一 般 字 符 常 量 一 般 字 符 常 量 是 用 一 对 单 引 号 括 起 来 的 一 个 字 符, 其 值 为 ASCII 码 值 例 如,'a','A','$' 以 及 '5' 等 都 是 合 法 的 字 符 常 量 注 意 :'a' 和 'A' 是 两 个 不 同 的 字 符 常 量 在 内 存 中, 字 符 数 据 是 以 ASCII 码 形 式 存 储 的, 以 整 数 表 示, 占 据 一 个 字 节 (2) 转 义 字 符 转 义 字 符 是 一 个 以 \ 开 头 的 特 定 字 符, 表 示 其 后 的 字 符 具 有 特 殊 意 义 例 如,'\n' 中 的 n 不 是 代 表 字 符 n, 而 是 代 表 回 车 换 行 的 意 思 常 用 的 转 义 字 符 如 表 2-2 所 示 表 2-2 C++ 的 基 本 数 据 类 型 字 符 形 式 ASCII 码 值 功 能 \0 0x00 NULL \a 0x07 响 铃 \b 0x08 退 格 (BackSpace 键 ) \t 0x09 水 平 制 表 (Tab 键 ) \f 0x0c 走 纸 换 页 \n 0x0a 回 车 换 行
31 22 C++ 程 序 设 计 续 表 字 符 形 式 ASCII 码 值 功 能 \v 0x0b 垂 直 制 表 \r 0x0d 回 车 ( 不 换 行 ) \\ 0x5c 字 符 \ \ 0x27 单 引 号 \ 0x22 双 引 号 \? 0x3f 问 号 \ddd 0ddd 1~3 位 八 进 制 数 所 代 表 的 字 符 \xhh 0xhh 1~2 位 十 六 进 制 数 所 代 表 的 字 符 反 斜 杠 \ 可 以 和 八 进 制 数 或 十 六 进 制 数 结 合 起 来 使 用, 以 表 示 相 当 于 该 字 符 的 ASCII 码 例 如,'\0x0a' 和 '\n' 同 义, 都 表 示 回 车 换 行 转 义 字 符 用 八 进 制 数 表 示 时, 最 多 是 三 位 数, 且 必 须 以 0 开 头, 范 围 为 '\000'~'\377' 转 义 字 符 用 十 六 进 制 数 表 示 时 是 两 位 数, 用 x 或 X 引 导, 表 示 范 围 为 '\x00'~'\xff' 4. 字 符 串 常 量 字 符 串 常 量 是 用 一 对 双 引 号 括 起 来 的 字 符 序 列 例 如,"a","123" 和 "hello" 等 都 是 字 符 串 常 量 在 C++ 中, 字 符 串 常 量 和 字 符 常 量 是 不 同 的 字 符 串 常 量 是 由 双 引 号 括 起 来 的 若 干 个 字 符, 这 些 字 符 在 内 存 中 连 续 存 储, 并 在 最 后 加 上 字 符 '\0' 作 为 字 符 串 结 束 的 标 志 例 如, 字 符 串 "HELLO" 在 内 存 中 占 连 续 6 个 内 存 单 元, 存 放 示 意 图 如 图 2-2 所 示 字 符 常 量 是 用 单 引 号 括 起 来 的 一 个 字 符, 它 在 内 存 中 只 占 一 个 字 节 所 以,"x" 和 'x' 是 不 同 的 H E L L O \0 图 2-2 字 符 串 "HELLO" 在 内 存 中 的 存 放 示 意 图 注 意 : 不 能 将 一 个 字 符 串 常 量 赋 给 字 符 常 量 例 如, 语 句 char c="abc" 是 错 误 的 5. 符 号 常 量 在 C++ 中, 可 以 用 一 个 标 识 符 来 表 示 一 个 常 数, 这 个 标 识 符 就 是 符 号 常 量 例 如, 在 求 解 圆 的 问 题 时 经 常 要 用 到 圆 周 率 π( 即 ), 如 果 用 符 号 π 表 示, 则 C++ 编 译 器 不 能 识 别 ; 如 果 用 表 示, 则 很 容 易 出 现 输 入 错 误 此 时, 可 以 通 过 一 个 容 易 理 解 和 记 忆 的 名 字 pi 来 代 表 圆 周 率 π, 这 样 就 不 会 发 生 上 述 问 题 pi 就 是 一 个 符 号 常 量 使 用 符 号 常 量 可 以 增 加 程 序 的 可 读 性 和 可 维 护 性 假 如 程 序 中 多 个 地 方 用 到 某 一 个 常 量, 修 改 该 常 量 时, 则 每 一 处 用 到 该 常 量 的 地 方 都 要 修 改 如 果 使 用 符 号 常 量, 则 只 需 修 改 一 个 地 方 即 可, 这 样 就 使 程 序 更 加 容 易 维 护 C++ 语 言 提 供 了 两 种 定 义 符 号 常 量 的 方 法 (1) 用 const 语 句 定 义 符 号 常 量 这 种 方 法 是 C++ 语 言 中 广 泛 采 用 的 定 义 符 号 常 量 的 方 法, 其 一 般 格 式 为 : const 数 据 类 型 符 号 常 量 = 表 达 式 ; 例 如 : const double pi = ; 该 语 句 定 义 了 一 个 符 号 常 量 pi, 其 值 为
32 第 2 章 基 本 数 据 类 型 和 表 达 式 23 注 意 : 在 定 义 符 号 常 量 时 必 须 进 行 初 始 化, 否 则 将 出 现 编 译 错 误 (2) 用 #define 语 句 定 义 符 号 常 量 这 是 C 语 言 中 定 义 符 号 常 量 的 方 法, 其 中 #define 是 预 处 理 指 令 其 缺 点 是 不 能 显 示 声 明 常 量 的 类 型 在 C++ 语 言 中 保 留 它, 仅 仅 是 为 了 与 C 语 言 保 持 兼 容 其 一 般 格 式 为 : #define 常 量 名 常 量 值 例 如 : #define pi 注 意 :#define 语 句 的 最 后 不 允 许 加 分 号 ; 变 量 变 量 是 指 在 程 序 运 行 过 程 中, 其 值 可 以 改 变 的 量 变 量 是 有 名 字 的, 在 内 存 中 占 据 一 定 的 存 储 单 元 C++ 语 言 中 使 用 变 量 前, 必 须 先 对 它 的 数 据 类 型 进 行 说 明, 以 便 告 诉 编 译 程 序 为 变 量 分 配 多 大 的 空 间 1. 变 量 的 命 名 变 量 的 命 名 要 遵 循 C++ 语 言 中 标 识 符 的 命 名 规 定 (1) 系 统 规 定 的 关 键 字 不 可 再 作 为 变 量 名 (2) 第 一 个 字 符 必 须 是 字 母 或 下 划 线, 后 跟 字 母 数 字 或 下 划 线, 中 间 不 能 有 空 格 (3) 命 名 变 量 应 尽 量 做 到 见 名 知 意, 这 样 有 助 于 记 忆, 增 加 可 读 性 (4) 在 命 名 变 量 时, 大 小 写 字 母 是 不 一 样 的 例 如,X1 和 x1 是 两 个 不 同 的 变 量 习 惯 上 用 小 写 字 母 命 名 变 量 2. 变 量 的 定 义 变 量 定 义 的 一 般 格 式 为 : 数 据 类 型 变 量 1, 变 量 2, 其 中 数 据 类 型 可 以 是 前 面 讲 过 的 各 种 数 据 类 型, 它 决 定 了 变 量 在 内 存 中 所 占 的 存 储 单 元 数 例 如 : int x,y,z; // 定 义 了 3 个 整 型 变 量 x y z float a,b,c; // 定 义 了 3 个 单 精 度 型 变 量 a b c 在 定 义 变 量 时, 必 须 注 意 变 量 类 型 的 选 择, 应 该 保 证 该 变 量 中 将 要 存 储 的 值 不 突 破 该 变 量 类 型 所 能 表 示 的 最 大 值 当 然, 也 不 能 因 此 就 将 每 个 变 量 都 声 明 成 表 示 范 围 最 大 的 类 型, 否 则 会 白 白 浪 费 存 储 空 间 3. 变 量 赋 值 与 初 始 化 在 使 用 已 定 义 的 变 量 前, 要 用 赋 值 运 算 符 = 对 它 进 行 赋 值 例 如 : int x1,y1; x1=10;y1=20; 也 可 以 在 变 量 定 义 时 直 接 进 行 初 始 化 例 如 : int x1=10,y1=20; 在 C++ 语 言 中, 还 有 另 外 一 种 方 式 给 变 量 赋 初 值, 例 如 : int i(1) 该 语 句 定 义 了 一 个 整 型 变 量 i, 其 初 值 为 1
33 24 C++ 程 序 设 计 2.4 运 算 符 和 表 达 式 C++ 语 言 有 丰 富 的 运 算 符, 能 构 成 多 种 表 达 式, 几 乎 所 有 的 操 作 都 可 以 使 用 运 算 符 来 处 理 表 达 式 是 用 运 算 符 将 各 种 运 算 对 象 ( 常 数 变 量 以 及 常 量 等, 也 称 操 作 数 ) 组 合 而 成 的 在 C++ 程 序 中, 表 达 式 与 在 数 学 中 学 到 的 类 似, 是 用 于 计 算 的 式 子, 是 计 算 求 值 的 基 本 单 位 运 算 符 和 数 学 中 的 概 念 一 样, 运 算 是 指 对 数 据 的 求 值 计 算, 如 加 减 运 算 等 运 算 符 给 出 了 计 算 的 类 型, 而 参 与 运 算 的 数 据 叫 操 作 数 C++ 语 言 定 义 了 丰 富 的 运 算 符, 这 些 运 算 符 按 所 要 求 的 操 作 数 的 多 少, 可 分 为 单 目 运 算 符 双 目 运 算 符 和 三 目 运 算 符 ; 按 运 算 符 的 运 算 性 质, 又 可 分 为 算 术 运 算 符 关 系 运 算 符 及 逻 辑 运 算 符 等 学 习 运 算 符 时, 要 注 意 以 下 几 点 (1) 运 算 符 的 功 能, 如 加 减 乘 除 等 (2) 与 操 作 数 的 关 系, 这 里 要 注 意 运 算 符 要 求 操 作 数 的 个 数 和 类 型 如 单 目 运 算 符 只 能 有 一 个 操 作 数, 如 果 有 两 个 操 作 数 参 与 运 算 就 会 出 现 编 译 错 误 而 取 余 运 算 符 %( 或 称 取 模 运 算 符 ) 则 要 求 参 与 运 算 的 两 个 操 作 数 类 型 必 须 为 整 型 (3) 运 算 符 的 优 先 级 别 当 一 个 表 达 式 中 含 有 多 个 运 算 符 时, 先 进 行 优 先 级 高 的 运 算, 后 进 行 优 先 级 低 的 运 算 当 表 达 式 中 出 现 了 多 个 相 同 优 先 级 的 运 算 时, 运 算 的 顺 序 就 要 看 运 算 符 的 结 合 性 了 (4) 运 算 符 的 结 合 性 结 合 性 是 指 当 一 个 操 作 数 左 右 两 边 的 运 算 符 优 先 级 相 同 时, 按 什 么 顺 序 进 行 运 算, 是 自 左 向 右, 还 是 自 右 向 左 例 如, 在 表 达 式 3*5/6 中,5 的 两 边 有 两 个 优 先 级 别 相 同 的 运 算 符 * 和 /, 按 照 从 左 到 右 的 结 合 性 应 该 先 进 行 乘 法, 再 进 行 除 法, 即 操 作 数 5 与 左 边 的 运 算 符 结 合, 称 左 结 合 性 当 然,C++ 语 言 中 也 有 结 合 方 向 从 右 到 左 的, 称 右 结 合 性 表 2-3 列 出 了 常 用 运 算 符 的 优 先 级 功 能 说 明 和 结 合 性 表 2-3 C++ 中 常 用 运 算 符 的 优 先 级 功 能 说 明 和 结 合 性 优 先 级 运 算 符 功 能 说 明 结 合 性 ( ) 改 变 优 先 级 :: 作 用 域 运 算 符 1 2 [ ] 数 组 下 标 运 算 符. > 成 员 选 择. * > * 成 员 指 针 选 择 * 指 针 运 算 符 & 取 地 址 sizeof 求 内 存 字 节 数! 逻 辑 求 反 ~ 按 位 求 反 增 1 减 1 运 算 符 + 取 正 取 负 运 算 符 左 结 合 右 结 合
34 第 2 章 基 本 数 据 类 型 和 表 达 式 25 优 先 级 运 算 符 功 能 说 明 结 合 性 3 * / % 乘 法 除 法 取 余 左 结 合 4 + 加 法 减 法 左 结 合 5 << >> 左 移 位 右 移 位 左 结 合 6 < > <= >= 小 于 大 于 小 于 等 于 大 于 等 于 左 结 合 7 ==!= 等 于 不 等 于 左 结 合 8 & 按 位 与 左 结 合 9 ^ 按 位 异 或 左 结 合 10 按 位 或 左 结 合 11 && 逻 辑 与 左 结 合 12 逻 辑 或 左 结 合 13?: 条 件 运 算 符 右 结 合 14 = += = * = /= %= <<= >>= &= ^= = 赋 值 运 算 符 续 表 右 结 合 15, 逗 号 运 算 符 左 结 合 1. 算 术 运 算 符 C++ 语 言 中 的 算 术 运 算 符 包 括 基 本 算 术 运 算 符 和 增 1 减 1 运 算 符 (1) 基 本 算 术 运 算 符 基 本 算 术 运 算 符 有 :+( 取 正 或 加 ) ( 取 负 或 减 ) *( 乘 ) /( 除 ) 和 %( 取 余 ) 其 中 +( 取 正 ) ( 取 负 ) 是 单 目 运 算 符, 其 余 是 双 目 运 算 符 上 述 运 算 符 与 其 在 数 学 中 的 意 义 优 先 级 和 结 合 性 基 本 相 同 不 过 必 须 注 意 的 是 / 运 算 符, 当 它 的 两 个 操 作 数 都 是 整 数 时, 其 计 算 结 果 应 是 除 法 运 算 后 所 得 商 的 整 数 部 分 例 如,5/2 的 结 果 是 2 要 完 成 通 常 意 义 上 的 除 法, 则 两 个 操 作 数 中 至 少 有 一 个 不 为 整 型 例 如,5.0/2 的 结 果 是 2.5 取 余 运 算 符 (%) 用 来 计 算 两 个 整 数 相 除 后 的 余 数 例 如,9%4 的 结 果 是 1,4%2 的 结 果 是 0 注 意 : 要 求 取 余 运 算 符 (%) 的 两 个 操 作 数 必 须 是 整 数 或 字 符 型 数 据 (2) 增 1 减 1 运 算 符 增 1 减 1 运 算 符 都 是 单 目 运 算 符, 这 两 个 运 算 符 都 有 前 置 和 后 置 两 种 形 式 前 置 形 式 是 指 运 算 符 在 操 作 数 的 前 面, 后 置 是 指 运 算 符 在 操 作 数 的 后 面 例 如 : i++; //++ 后 置 --j; //-- 前 置 无 论 是 前 置 还 是 后 置, 这 两 个 运 算 符 的 作 用 都 是 使 操 作 数 的 值 增 1 或 减 1 但 操 作 数 和 运 算 符 组 成 的 表 达 式 不 同, 最 后 的 结 果 也 并 不 相 同 假 设 i=2,j=2, 看 下 面 的 两 个 例 子 : i++; ++j; 经 过 计 算 后, 第 一 个 表 达 式 的 值 为 2,i 值 为 3; 第 二 个 表 达 式 值 为 3,j 值 为 3 即 前 置 形 式 是 先 计 算 操 作 数 的 值 ( 增 1 或 减 1), 后 把 操 作 数 的 值 作 为 表 达 式 的 结 果 ; 而 后 置 形 式 是 先 将 操 作 数 的 值 作 为 表 达 式 的 结 果, 然 后 把 操 作 数 的 值 增 1 或 减 1 这 一 点 在 这 种 表 达 式 被 当 作 操
35 26 C++ 程 序 设 计 作 数 继 续 参 与 其 他 运 算 时 要 特 别 注 意 例 如, 假 设 a=5, 分 别 计 算 下 面 两 个 表 达 式 的 结 果 b = a ++ 或 b = ++ a 执 行 上 述 两 个 表 达 式 后,a 的 值 都 变 为 6, 但 b 的 值 却 不 一 样 第 一 个 表 达 式 的 结 果 为 b=5, 原 因 在 于 先 取 值 后 计 算, 表 达 式 先 将 变 量 a 的 值 赋 值 给 变 量 b, 然 后 再 增 1 第 二 个 表 达 式 的 结 果 为 b=6, 是 因 为 先 计 算 后 取 值 的 缘 故, 变 量 a 先 增 1, 然 后 再 赋 值 给 变 量 b 所 以, 尽 管 两 个 表 达 式 类 似, 但 计 算 结 果 却 不 同 在 进 行 算 术 运 算 时, 还 需 注 意 计 算 中 的 溢 出 问 题 在 计 算 机 中 每 种 基 本 数 据 类 型 都 有 一 定 的 取 值 范 围 对 于 实 数, 如 果 运 算 结 果 超 出 范 围, 程 序 将 被 异 常 中 止 另 外, 整 数 或 实 数 被 零 除 也 会 导 致 程 序 异 常 中 止 但 C++ 语 言 并 不 认 为 整 数 溢 出 是 一 个 错 误 事 实 上, 在 C++ 语 言 中 有 时 还 需 要 利 用 整 数 溢 出 来 进 行 一 些 有 目 的 的 编 程 当 然, 程 序 员 也 有 义 务 在 程 序 中 处 理 好 溢 出, 避 免 计 算 错 误 2. 关 系 运 算 符 关 系 运 算 符 用 于 比 较 两 个 操 作 数 的 大 小, 其 比 较 的 结 果 是 一 个 布 尔 型 的 值 当 两 个 操 作 数 满 足 关 系 运 算 符 指 定 的 关 系 时, 表 达 式 的 值 为 true, 否 则 为 false 在 C++ 语 言 中, 关 系 运 算 符 都 是 双 目 运 算 符, 共 有 6 个 :<( 小 于 ) <=( 小 于 或 等 于 ) > ( 大 于 ) >=( 大 于 或 等 于 ) ==( 等 于 ) 和!=( 不 等 于 ) 其 中 前 4 种 和 后 2 种 属 于 不 同 的 优 先 级, 前 4 种 的 优 先 级 高 于 后 2 种 在 C 语 言 中 没 有 布 尔 类 型, 它 采 用 整 数 1 和 0 表 示 真 和 假 C++ 语 言 中 虽 然 有 布 尔 类 型, 但 它 仍 然 继 承 了 C 语 言 的 规 定,true 等 于 1,false 等 于 0 例 如, 表 达 式 2>=3 的 结 果 为 0(false) 所 以, 关 系 运 算 符 的 比 较 结 果 可 以 作 为 算 术 运 算 中 的 操 作 数 关 系 运 算 符 的 操 作 数 可 以 是 任 何 基 本 数 据 类 型 的 数 据 但 由 于 实 数 在 计 算 机 中 只 能 近 似 地 表 示, 所 以, 一 般 不 能 直 接 进 行 相 等 比 较 当 需 要 进 行 这 样 的 比 较 时, 通 常 的 作 法 是 指 定 一 个 极 小 的 精 度 值, 当 两 个 实 数 的 差 在 这 个 精 度 之 内 时, 就 认 为 两 实 数 相 等, 否 则 认 为 不 相 等 在 使 用 关 系 运 算 符 时 还 应 注 意 以 下 两 点 (1) 不 要 把 关 系 运 算 符 = = 误 用 为 赋 值 运 算 符 = 比 如, 如 果 将 判 断 变 量 x 是 否 等 于 8 的 关 系 表 达 式 x= =8 写 成 x=8, 则 该 表 达 式 的 值 永 远 为 true( 真 ), 而 不 管 x 原 来 的 值 是 多 少 也 不 要 将 不 等 于 运 算 符!= 写 成 其 他 语 言 中 的 不 等 于 运 算 符 <> (2) 对 于 数 学 中 表 示 x 大 于 等 于 5, 且 x 小 于 等 于 20 的 数 学 关 系 式 5 x 20, 如 果 写 成 下 面 的 表 达 式 : 5 <= x <= 20 则 在 C++ 中 是 错 误 的 这 种 错 误 是 一 种 语 义 上 的 错 误, 而 不 是 语 法 上 的 错 误, 编 译 器 查 不 出 来, 编 译 时 不 会 报 告 错 误 但 运 行 时, 不 论 x 为 何 值 ( 比 如 为 3 或 60), 表 达 式 的 值 都 是 真, 所 以 这 种 错 误 较 隐 蔽, 不 易 被 发 现, 希 望 引 起 注 意 正 确 的 表 达 式 应 该 为 : 5 <= x && x <= 逻 辑 运 算 符 逻 辑 运 算 符 共 有 3 个 :1 个 单 目 运 算 符!( 逻 辑 求 反 ), 两 个 双 目 运 算 符 &&( 逻 辑 与 ) 和 ( 逻
36 第 2 章 基 本 数 据 类 型 和 表 达 式 27 辑 或 ) 其 中 逻 辑 与 的 优 先 级 比 逻 辑 或 高 逻 辑 运 算 的 结 果 是 逻 辑 值 参 与 逻 辑 运 算 的 操 作 数 可 以 是 任 一 基 本 数 据 类 型 的 数 据, 在 进 行 判 断 时, 系 统 将 视 非 零 值 为 真, 零 为 假 对 于 单 目 运 算 符!( 逻 辑 求 反 ), 若 其 操 作 数 为 false(0), 则 运 算 结 果 为 true(1), 否 则 为 false(0) 例 如,!4 的 结 果 为 0 对 于 &&( 逻 辑 与 ) 运 算 符, 只 要 两 个 操 作 数 中 有 一 个 为 false(0), 运 算 结 果 就 为 false(0), 否 则 为 true(1) 例 如,3&&4 的 结 果 为 1 对 于 ( 逻 辑 或 ) 运 算 符, 只 要 两 个 操 作 数 中 有 一 个 为 true(1), 运 算 结 果 就 为 true(1), 否 则 为 false(0) 例 如,3 0 的 结 果 为 1 注 意 : 关 系 运 算 和 逻 辑 运 算 的 结 果 若 为 真, 其 值 为 1; 若 为 假, 其 值 为 0 4. 赋 值 运 算 符 C++ 中 的 赋 值 运 算 符 分 为 两 种 : 简 单 赋 值 运 算 符 和 复 合 赋 值 运 算 符 (1) 简 单 赋 值 运 算 符 简 单 赋 值 运 算 符 有 = 其 表 达 式 的 一 般 形 式 为 : 变 量 = 表 达 式 该 表 达 式 执 行 时, 先 计 算 赋 值 运 算 符 右 部 表 达 式 的 值, 然 后 将 它 赋 值 给 左 部 变 量 (2) 复 合 赋 值 运 算 符 复 合 赋 值 运 算 符 由 一 个 数 值 型 运 算 符 和 基 本 赋 值 运 算 符 组 合 而 成, 共 有 10 个, 分 别 为 +=, -=,*=,/=,%=,<<=,>>=,&=,^= 和 = 如 果 以 # 表 示 数 值 型 运 算 符, 则 复 合 赋 值 表 达 式 的 一 般 形 式 为 : 变 量 #= 表 达 式 该 表 达 式 等 价 于 : 变 量 = 变 量 # 表 达 式 即 先 用 左 部 变 量 和 右 部 表 达 式 做 数 值 运 算, 然 后 将 运 算 结 果 赋 给 左 部 变 量 例 如 : a += 5 等 价 于 a = a+5 x *=6 等 价 于 x = x * 6 m %=7 等 价 于 m = m % 7 使 用 复 合 赋 值 运 算 符 不 仅 书 写 简 练, 而 且 经 过 编 译 以 后 生 成 的 代 码 少 5. 位 运 算 符 C++ 语 言 继 承 了 C 语 言 能 进 行 位 算 的 优 点, 提 供 了 6 个 位 运 算 符 :~( 按 位 求 反 ) &( 按 位 与 ) ( 按 位 或 ) ^( 按 位 异 或 ) <<( 右 移 位 ) 和 >>( 左 移 位 ) 其 中 ~( 按 位 求 反 ) 是 单 目 运 算 符, 其 余 都 是 双 目 运 算 符 位 运 算 符 是 对 其 操 作 数 按 二 进 制 形 式 逐 位 进 行 运 算, 参 与 运 算 的 操 作 数 都 应 为 整 数, 不 能 是 实 型 数 (1)~( 按 位 求 反 ): 其 作 用 是 对 一 个 二 进 制 数 的 每 一 位 求 反, 即 0 1,1 0 (2)&( 按 位 与 ): 其 作 用 是 对 两 个 操 作 数 对 应 的 每 一 位 分 别 进 行 逻 辑 与 操 作 两 操 作 数 对 应 位 都 是 1, 则 该 位 运 算 结 果 为 1, 否 则 该 位 运 算 结 果 为 0 (3) ( 按 位 或 ): 其 作 用 是 对 两 个 操 作 数 对 应 的 每 一 位 分 别 进 行 逻 辑 或 操 作 两 操 作 数 对 应 位 中 有 1 位 是 1, 则 该 位 运 算 结 果 为 1, 否 则 该 位 运 算 结 果 为 0
37 28 C++ 程 序 设 计 (4)^( 按 位 异 或 ): 其 作 用 是 对 两 个 操 作 数 对 应 的 每 一 位 分 别 进 行 逻 辑 异 或 操 作 两 操 作 数 对 应 位 的 值 不 同, 则 该 位 运 算 结 果 为 1, 否 则 该 位 运 算 结 果 为 0 (5)<<( 右 移 位 ): 将 左 操 作 数 的 各 二 进 制 位 右 移, 右 移 位 数 由 右 操 作 数 给 出 右 移 1 位 相 当 于 将 操 作 数 除 以 2 例 如, 表 达 式 4<<1 的 结 果 为 2 (6)>>( 左 移 位 ): 将 左 操 作 数 的 各 二 进 制 位 左 移, 左 移 位 数 由 右 操 作 数 给 出 左 移 1 位 相 当 于 将 操 作 数 乘 以 2 例 如, 表 达 式 4>>1 的 结 果 为 8 注 意 : 移 位 运 算 的 结 果 就 是 位 运 算 表 达 式 的 值, 参 与 运 算 的 两 个 操 作 数 的 值 并 没 有 发 生 变 化 6. 其 他 运 算 符 (1) 条 件 运 算 符 条 件 运 算 符?: 是 一 个 三 目 运 算 符, 其 使 用 的 一 般 形 式 为 : 表 达 式 1? 表 达 式 2: 表 达 式 3 该 表 达 式 执 行 时, 先 分 析 表 达 式 1, 其 值 为 真 时, 则 表 达 式 2 的 值 为 条 件 表 达 式 的 值, 否 则 表 达 式 3 的 值 为 条 件 表 达 式 的 值 条 件 运 算 符 的 优 先 级 低 于 算 术 运 算 符 关 系 运 算 符 和 逻 辑 运 算 符, 高 于 赋 值 运 算 符, 结 合 性 为 从 右 到 左 例 如, 求 a 和 b 中 较 大 者, 可 写 成 下 面 的 表 达 式 : max = a > b? a : b (2) 逗 号 运 算 符 由 逗 号 运 算 符 构 成 的 表 达 式 称 为 逗 号 表 达 式, 其 一 般 形 式 为 : 表 达 式 1, 表 达 式 2,, 表 达 式 n 逗 号 表 达 式 的 执 行 规 则 是 从 左 到 右, 逐 个 表 达 式 执 行, 最 后 一 个 表 达 式 的 值 是 该 逗 号 表 达 式 的 值 注 意 : 逗 号 运 算 符, 的 优 先 级 最 低 例 如, 表 达 式 a=3,a+l,a*a 的 结 果 为 表 达 式 表 达 式 是 由 运 算 符 和 操 作 数 组 成 的 符 合 C++ 语 法 规 则 的 式 子, 其 目 的 是 用 来 说 明 一 个 计 算 过 程 表 达 式 中 的 操 作 数 包 括 常 量 变 量 和 函 数 等 所 有 的 表 达 式 都 有 一 个 值, 即 返 回 结 果 C++ 语 言 中 常 见 的 表 达 式 有 : 算 术 表 达 式 关 系 表 达 式 逻 辑 表 达 式 条 件 表 达 式 逗 号 表 达 式 及 赋 值 表 达 式 等 在 书 写 表 达 式 时, 必 须 注 意 运 算 符 的 优 先 级 与 结 合 性, 确 保 列 出 的 表 达 式 的 实 际 求 值 顺 序 与 自 己 所 要 求 的 一 致 必 要 时 可 加 括 号 以 便 于 理 解, 甚 至 改 变 优 先 级 括 号 的 使 用 可 以 嵌 套 在 计 算 时, 先 做 内 括 号, 再 做 外 括 号 另 外, 还 应 注 意, 在 表 达 式 中 连 续 出 现 两 个 运 算 符 时, 最 好 用 空 格 分 隔 例 如 : i + ++ j i +++ j i ++ + j 上 面 的 3 个 表 达 式 都 连 续 出 现 了 两 个 运 算 符 其 中 在 第 1 第 3 个 表 达 式 中 运 算 符 用 空 格
38 第 2 章 基 本 数 据 类 型 和 表 达 式 29 分 隔 开 了, 如 何 运 算 非 常 明 确 第 2 个 表 达 式 的 意 义 就 不 太 明 了, 实 际 上 该 表 达 式 和 第 3 个 表 达 式 意 义 相 同, 原 因 在 于 增 1 运 算 符 (++) 的 优 先 级 别 高 于 加 法 运 算 符 (+), 而 且 ++ 运 算 符 的 结 合 性 为 右 结 合, 但 读 者 分 析 该 表 达 式 是 如 何 运 算 的 可 能 有 点 费 劲 因 此, 在 连 续 出 现 两 个 运 算 符 时 加 空 格 是 有 必 要 的 当 然, 这 里 采 用 加 括 号 的 方 法 也 可 以 达 到 同 样 的 目 的 1. 算 术 表 达 式 算 术 表 达 式 是 由 算 术 运 算 符 与 操 作 数 组 成 的, 其 表 达 式 的 值 是 一 个 数 值, 表 达 式 的 类 型 由 运 算 符 和 操 作 数 共 同 确 定 例 2.1 算 术 表 达 式 的 计 算 #include"iostream.h" void main() int i=4,j=5,k=6; int x; x=i+j k; cout<<"x="<<x<<endl; // 输 出 x=3 x=(i+j)*k/2; cout<<"x="<<x<<endl; // 输 出 x=27 x=25*4/2%k; cout<<"x="<<x<<endl; // 输 出 x=2 例 2.2 增 1 表 达 式 的 计 算 #include"iostream.h" void main() int i,j,k; i=4; j=i++; cout<<"i="<<i<<'\t'<<"j="<<j<<endl; i=4; k=++i; cout<<"i="<<i<<'\t'<<"k="<<k<<endl; double x=2.5; cout<<x (x+0.5)*2<<endl; // 操 作 数 类 型 不 相 同 运 行 程 序 后, 输 出 结 果 为 : i=4 j=4 i=5 k= 关 系 表 达 式 与 逻 辑 表 达 式
39 30 C++ 程 序 设 计 关 系 表 达 式 是 由 关 系 运 算 符 和 操 作 数 组 成 的, 而 逻 辑 表 达 式 由 逻 辑 运 算 符 与 操 作 数 组 成 这 两 种 表 达 式 的 值 都 应 是 1(true) 或 0(false) 它 们 常 出 现 在 条 件 语 句 和 循 环 语 句 中, 用 于 决 定 问 题 的 执 行 方 法 例 2.3 关 系 表 达 式 与 逻 辑 表 达 式 的 计 算 #include"iostream.h" void main() int x=3,y=5,z; z=(x>0) (y<10); cout<<"z="<<z<<endl; // 输 出 z=1, 表 示 true z=(x= =0)&&(y<10); cout<<"z="<<z<<endl; // 输 出 z=0, 表 示 false z=!(x= =3); cout<<"z="<<z<<endl; // 输 出 z=0, 表 示 false 3. 赋 值 表 达 式 赋 值 表 达 式 由 赋 值 运 算 符 与 操 作 数 组 成 C++ 语 言 共 提 供 了 11 个 赋 值 运 算 符 :=,+=, =, *=,/=,%=,<<=,>>=,&=,^= 和 = 其 中 = 是 基 本 赋 值 运 算 符, 另 外 10 个 是 复 合 赋 值 运 算 符 赋 值 运 算 符 的 结 合 性 是 自 右 向 左 赋 值 表 达 式 的 作 用 就 是 把 赋 值 运 算 符 右 边 表 达 式 的 值 赋 给 左 边 的 变 量 赋 值 表 达 式 的 类 型 为 左 边 变 量 的 类 型, 其 值 为 赋 值 后 左 边 变 量 的 值 例 如 : x=2.6 // 表 达 式 的 值 为 2.6 在 C++ 语 言 中 还 可 以 连 续 赋 值, 例 如 : x=y=z=2.6 由 赋 值 运 算 符 的 结 合 性 知 : 这 个 表 达 式 从 右 向 左 运 算, 首 先 将 z 赋 值 为 2.6, 表 达 式 z=2.6 的 值 也 为 2.6, 接 着 表 达 式 z=2.6 的 值 赋 给 y, 使 y 的 值 为 2.6, 最 后 x 被 赋 值 为 2.6, 整 个 表 达 式 的 值 也 为 2.6 例 2.4 分 析 下 面 程 序 的 输 出 结 果 #include"iostream.h" void main() int m=3,n=4,k; k=m++ ---n; cout<<"k="<<k<<endl; char x='m',y='n'; int z; z=y<x; cout<<"z="<<z<<endl; z=(y= =x+1);
40 第 2 章 基 本 数 据 类 型 和 表 达 式 31 cout<<"z="<<z<<endl; z=('y'!='y'); cout<<"z="<<z<<endl; int a=1,b=3,c=5; a+=b*=c =2; cout<<"a="<<a<<','<<"b="<<b<<','<<"c="<<c<<endl; 运 行 程 序 后, 输 出 结 果 为 : k=0 z=0 z=1 z=1 a=10,b=9,c=3 4. 表 达 式 中 数 据 类 型 的 转 换 表 达 式 的 值 和 类 型 由 运 算 符 和 参 与 运 算 的 操 作 数 决 定 当 各 操 作 数 的 数 据 类 型 相 同 时, 表 达 式 的 类 型 就 是 操 作 数 的 类 型 但 是 当 参 与 运 算 的 操 作 数 的 数 据 类 型 不 一 致 时, 即 C++ 要 在 不 同 类 型 的 数 据 之 间 进 行 混 合 运 算 时,C++ 语 言 就 需 要 对 这 些 不 同 类 型 的 操 作 数 进 行 类 型 转 换 表 达 式 中 数 据 类 型 的 转 换 有 两 种 : 隐 含 转 换 和 强 制 转 换 (1) 隐 含 转 换 当 操 作 数 的 类 型 不 一 致 时, 表 达 式 的 类 型 就 取 决 于 操 作 数 中 类 型 最 高 的 操 作 数 类 型,C++ 语 言 将 自 动 进 行 类 型 转 换, 隐 含 转 换 的 示 意 图 如 图 2-3 所 示, 其 转 换 规 则 如 下 double float 1 float 型 数 据 自 动 转 换 成 double 型,char 和 short 型 数 据 自 动 转 换 成 int 型 这 是 横 向 箭 头 的 含 义 long 2 当 操 作 数 类 型 不 同 时, 将 按 照 纵 向 箭 头 来 进 行 类 型 转 换 例 如, 一 个 long 型 的 操 作 数 和 一 个 double 型 的 操 作 数 进 行 运 算 时, 则 unsigned long 型 会 自 动 转 换 成 double 型 可 以 看 出, 隐 含 转 换 是 由 取 值 范 围 小 的 类 型 向 取 值 范 围 大 的 类 型 int char,short 转 换, 以 确 保 在 转 换 数 据 类 型 时 不 会 造 成 数 据 丢 失 图 2-3 隐 含 转 换 示 意 图 注 意 : 隐 含 转 换 是 由 编 译 系 统 自 动 完 成 的, 它 实 际 上 并 不 改 变 操 作 数 的 数 据 类 型, 只 是 在 计 算 表 达 式 值 时, 临 时 改 变 操 作 数 的 数 据 类 型, 计 算 完 成 后, 操 作 数 仍 保 持 原 有 的 数 据 类 型 (2) 强 制 转 换 强 制 转 换 的 作 用 是 将 表 达 式 的 类 型 强 制 地 转 换 成 指 定 的 数 据 类 型 其 一 般 形 式 为 : 或 数 据 类 型 ( 表 达 式 ) ( 数 据 类 型 ) 表 达 式 例 如 : double(a) // 将 a 强 制 转 换 成 double 型 float(5%3) // 将 5%3 的 结 果 转 换 成 float 型 注 意 : 如 果 出 现 将 高 类 型 转 换 成 低 类 型 的 情 形 时, 将 造 成 数 据 精 度 的 损 失 因 此, 这 是 一
41 32 C++ 程 序 设 计 种 不 安 全 的 类 型 转 换 2.5 控 制 语 句 C++ 语 言 支 持 结 构 化 程 序 设 计 结 构 化 程 序 有 3 种 基 本 结 构 : 顺 序 结 构 选 择 结 构 和 循 环 结 构, 这 3 种 结 构 又 是 由 语 句 来 构 成 的 语 句 是 表 达 算 法 命 令 或 编 译 指 示 的 基 本 语 言 单 位,C++ 源 程 序 就 是 由 各 种 语 句 组 成 的 在 C++ 语 言 中, 把 常 量 变 量 运 算 符 和 表 达 式 等 按 一 定 的 句 法 规 则 进 行 组 合, 以 分 号 结 束 就 可 构 成 各 种 语 句 语 句 可 用 于 计 算 表 达 式 的 值, 控 制 程 序 执 行 的 顺 序 因 此, 熟 练 地 掌 握 各 种 语 句, 是 学 好 一 门 计 算 机 语 言 的 基 础 要 掌 握 C++ 语 句, 就 必 须 抓 住 两 个 基 本 点 : 语 法 和 语 义 语 法 就 是 语 句 的 书 写 规 则 在 C++ 中, 各 种 语 句 都 有 其 特 定 的 书 写 形 式, 使 用 时 必 须 按 照 规 定 的 格 式 书 写, 否 则 编 译 程 序 将 不 予 编 译 或 编 译 出 错 误 的 程 序 语 义 就 是 语 句 的 含 义 和 作 用 C++ 中 的 各 种 语 句, 都 有 其 特 定 的 功 能, 必 须 准 确 地 理 解 和 掌 握 C++ 语 言 提 供 了 丰 富 的 语 句, 大 致 可 分 为 : 表 达 式 语 句 复 合 语 句 选 择 语 句 循 环 语 句 和 转 移 语 句 表 达 式 语 句 表 达 式 语 句 是 由 一 个 表 达 式 加 上 分 号 组 成 例 如 : int i; // 将 i 声 明 为 整 型 变 量 的 语 句 ; // 空 语 句 a=3*4+5; // 赋 值 语 句 如 果 表 达 式 语 句 中 的 表 达 式 为 空 就 成 为 空 语 句 空 语 句 仅 由 分 号 组 成, 在 程 序 中 不 做 任 何 操 作 复 合 语 句 复 合 语 句 也 称 块 语 句, 是 由 两 条 或 两 条 以 上 的 语 句 组 成, 并 用 括 起 来 的 语 句 复 合 语 句 在 语 法 上 相 当 于 一 条 语 句 注 意 : 在 复 合 语 句 的 右 括 号 后 不 再 需 要 分 号 复 合 语 句 可 以 出 现 在 任 何 地 方, 常 用 来 作 为 if 语 句 的 if 体 else 体 或 循 环 语 句 的 循 环 体 等 复 合 语 句 还 可 以 嵌 套 选 择 语 句 选 择 语 句 是 对 给 定 的 条 件 进 行 判 定, 并 根 据 判 定 结 果 决 定 执 行 哪 些 操 作, 不 执 行 哪 些 操 作 C++ 语 言 中 提 供 的 选 择 语 句 有 if 语 句 和 switch 语 句 1.if 语 句 if 语 句 用 来 有 条 件 地 执 行 某 一 语 句 系 列 if 语 句 主 要 有 3 种 语 法 格 式 (1)if( 表 达 式 )
42 语 句 ; (2)if( 表 达 式 ) 语 句 1; else 语 句 2; (3)if( 表 达 式 1) < 语 句 1> elseif( 表 达 式 2) < 语 句 2> elseif( 表 达 式 3) < 语 句 3> elseif( 表 达 式 n) < 语 句 n> 第 2 章 基 本 数 据 类 型 和 表 达 式 33 else < 语 句 n + 1> 其 中 的 表 达 式 一 般 是 关 系 表 达 式, 并 且 表 达 式 必 须 用 () 括 起 来 语 句 可 以 是 一 条 语 句, 也 可 以 是 多 条 语 句 如 果 只 有 一 条 语 句, 则 可 以 省 略 对 于 格 式 (1): 首 先 计 算 表 达 式 的 值, 如 果 表 达 式 的 值 不 为 0, 表 示 条 件 判 定 为 真, 花 括 号 内 的 语 句 将 被 执 行, 否 则 将 执 行 后 面 的 语 句 对 于 格 式 (2): 首 先 计 算 表 达 式 的 值, 如 果 表 达 式 条 件 判 定 为 真, 则 执 行 语 句 1, 否 则 将 执 行 语 句 2 对 于 格 式 (3): 首 先 计 算 表 达 式 1 的 值, 如 果 表 达 式 1 条 件 判 定 为 真, 则 执 行 语 句 1, 否 则 判 定 表 达 式 2, 如 果 条 件 判 定 为 真, 则 执 行 语 句 2 依 此 类 推, 直 到 所 有 的 表 达 式 条 件 均 不 满 足, 此 时 将 执 行 语 句 n+1 该 格 式 实 际 上 提 供 了 多 重 条 件 选 择 例 2.5 if 语 句 的 应 用 #include"iostream.h" void main() float score; cout<<"please enter your score:"<<endl; cin>>score; if (score>=60) cout<<"passed!"<<endl; if (score<60) cout<<"no passed!"<<endl; cout<<" You should do your best to study"<<endl;
43 34 C++ 程 序 设 计 运 行 程 序 后, 屏 幕 上 输 出 显 示 : Please enter your score: 提 示 用 户 输 入 成 绩, 当 用 户 输 入 成 绩 信 息 后, 程 序 会 根 据 用 户 的 输 入, 输 出 显 示 相 应 的 信 息 如 输 入 70, 则 显 示 : Passed! 例 2.6 利 用 if else 语 句 改 写 例 2.5 #include"iostream.h" void main() float score; cout<<"please enter your score:"<<endl; cin>>score; if (score>=60) cout<<"passed!"<<endl; else cout<<"no passed!"<<endl; cout<<" You should do your best to study"<<endl; 例 2.7 比 较 两 个 数 的 大 小 #include"iostream.h" void main() int x,y; cout<<"please input x,y:"<<endl; cin>>x>>y; if (x!=y) if (x>y) cout<<"x>y"<<endl; else cout<<"x<y"<<endl; else cout<<"x=y"<<endl; 例 2.7 实 际 就 是 if 语 句 的 嵌 套 使 用 程 序 执 行 后, 屏 幕 上 输 出 显 示 : Please input x,y: 计 算 机 提 示 用 户 输 入 两 个 x 和 y 的 值 当 用 户 输 入 后, 计 算 机 将 显 示 相 应 的 判 断 结 果 例 如,
44 第 2 章 基 本 数 据 类 型 和 表 达 式 35 输 入 1 和 2 后 将 显 示 x<y 的 判 断 结 果 注 意 : 在 if 语 句 嵌 套 使 用 时, 一 定 要 注 意 if 和 else 的 配 对 问 题 C++ 语 言 中 采 用 的 是 就 近 原 则, 即 把 一 个 else 和 离 它 最 近 的 那 个 if 配 对 当 然, 对 于 例 2.7 要 对 多 个 条 件 进 行 判 断 的 情 况, 也 可 以 利 用 格 式 (3) 来 编 写 程 序 例 2.8 利 用 格 式 (3) 改 写 例 2.7 #include"iostream.h" void main() int x,y; cout<<"please input x,y:"<<endl; cin>>x>>y; if (x= =y) cout<<"x=y"<<endl; elseif (x>y) cout<<"x>y"<<endl; else cout<<"x<y"<<endl; 2.switch 语 句 在 if 语 句 嵌 套 使 用 时, 如 果 嵌 套 层 数 太 多, 将 使 程 序 变 得 难 于 理 解 为 此,C++ 语 言 提 供 了 switch 语 句 来 简 化 这 一 过 程 switch 语 句 又 称 开 关 语 句, 其 语 法 格 式 为 : switch( 表 达 式 ) case 常 量 表 达 式 1: 语 句 1; case 常 量 表 达 式 2: 语 句 2; case 常 量 表 达 式 n: 语 句 n; default: 语 句 n+1; 其 中,switch,case 和 default 是 关 键 字, 常 量 表 达 式 通 常 为 整 型 数 值 和 字 符 常 量, 语 句 1~ 语 句 n 是 由 1 条 或 多 条 语 句 组 成 的 语 句 段, 也 可 以 是 空 语 句 如 果 是 多 条 语 句, 可 以 不 用 花 括 号 括 起 来 switch 语 句 的 执 行 过 程 : 首 先 计 算 switch 语 句 中 的 表 达 式, 然 后 按 先 后 顺 序 将 得 到 的 结 果 与 case 中 的 常 量 表 达 式 的 值 进 行 比 较 如 果 两 者 相 等, 程 序 就 转 到 相 应 case 处 开 始 顺 序 执 行 如 果 没 有 找 到 相 匹 配 的 结 果, 就 从 default 处 开 始 执 行 如 果 没 有 default, 则 转 到 switch 语 句 的 下 一 条 语 句 继 续 执 行 大 多 数 情 况 下, 我 们 都 希 望 switch 语 句 在 执 行 完 某 一 case 后 面 的 语 句 时, 不 再 执 行 其 他 的 case 和 default 分 支, 直 接 开 始 执 行 switch 语 句 后 面 的 语 句 这 时 需 要 在 每 个 case 的 末 尾 加 上 一 条 break 语 句, 表 示 跳 出 switch 语 句, 不 再 执 行 下 面 的 case 和 default 分 支 否 则, 将 把 其 后 面 的 case 和 default 分 支 都 执 行 完 毕 例 2.9 根 据 考 试 成 绩 的 等 级 给 出 百 分 制 分 数 段
45 36 C++ 程 序 设 计 #include"iostream.h" void main() char grade; cout<<" 请 输 入 成 绩 :"<<endl; cin>>grade; if (grade>='a' && grade<='z') grade =32; // 若 输 入 小 写 字 母, 则 转 化 为 大 写 字 母 switch(grade) case 'A':cout<<"90~100"<< endl; case 'B':cout<<"80~89"<< endl; case 'C':cout<<"70~79"<< endl; case 'D':cout<<"60~69"<< endl; case 'E':cout<<"60 分 以 下 "<< endl; 运 行 程 序 后, 屏 幕 上 将 显 示 字 符 串 请 输 入 成 绩 : 假 设 输 入 B 后, 将 输 出 结 果 : 80~89 70~79 60~69 60 分 以 下 显 然, 这 样 的 输 出 结 果 是 不 符 合 原 意 的, 原 因 就 在 于 没 有 用 break 语 句 作 为 每 个 case 的 结 束 语 句 现 修 改 例 2.9 程 序 如 下 : switch(grade) case 'A':cout<<"90~100"<< endl;break; case 'B':cout<<"80~89"<< endl; break; case 'C':cout<<"70~79"<< endl; break; case 'D':cout<<"60~69"<< endl; break; case 'E':cout<<"60 分 以 下 "<< endl; break; 再 运 行 程 序, 然 后 输 入 成 绩 B, 将 输 出 结 果 : 80~ 循 环 语 句 在 程 序 设 计 中 经 常 遇 到 需 要 重 复 执 行 的 操 作, 这 些 操 作 可 以 使 用 循 环 语 句 来 实 现 循 环 语 句 使 得 程 序 在 给 定 条 件 满 足 时, 能 够 重 复 地 执 行 某 些 操 作 C++ 语 言 提 供 了 3 种 循 环 语 句 :while 循 环 语 句 do while 循 环 语 句 和 for 循 环 语 句
46 第 2 章 基 本 数 据 类 型 和 表 达 式 37 1.while 循 环 语 句 while 循 环 语 句 的 语 法 形 式 为 : while( 表 达 式 ) 循 环 体 ; 其 中,while 是 关 键 字 表 达 式 可 以 是 C++ 语 言 中 任 何 合 法 的 表 达 式, 它 用 来 判 断 执 行 循 环 体 的 条 件, 根 据 循 环 条 件 决 定 是 否 执 行 循 环 体 循 环 体 由 语 句 组 成, 可 以 是 一 条 语 句, 也 可 以 是 多 条 语 句 while 循 环 语 句 的 执 行 过 程 : 先 计 算 表 达 式 的 值, 若 其 值 为 true(1) 或 其 他 非 0 值, 则 执 行 循 环 体 语 句 ; 若 其 值 为 false(0), 则 退 出 循 环 体, 直 接 转 移 去 执 行 while 循 环 语 句 后 的 语 句 当 执 行 一 次 循 环 体 后, 再 次 计 算 表 达 式 的 值, 如 果 其 值 为 true(1) 或 其 他 非 0 值, 则 再 次 执 行 循 环 体 语 句, 直 至 表 达 式 值 为 零, 退 出 循 环 体 while 循 环 执 行 过 程 如 图 2-4 所 示 例 2.10 编 程 计 算 1~100 之 和 #include"iostream.h" void main() int i=1,sum=0; while(i<=100) sum+=i; i++; cout<<"sum="<<sum<<endl; 程 序 运 行 后, 输 出 结 果 : 5050 真 表 达 式 循 环 体 假 图 2-4 while 循 环 执 行 过 程 在 使 用 while 循 环 语 句 时, 为 保 证 不 出 现 死 循 环, 在 循 环 体 内 应 该 包 含 改 变 循 环 变 量 的 语 句 当 然, 也 可 采 用 在 循 环 体 内 使 用 break 等 转 移 语 句 的 方 法 对 于 while(1) 这 样 的 循 环, 表 达 式 中 的 值 永 远 非 0, 就 必 须 在 循 环 体 内 包 含 break 等 转 移 语 句 注 意 : 在 使 用 循 环 语 句 时, 一 定 要 设 法 改 变 循 环 的 终 止 条 件, 使 之 在 有 限 次 循 环 之 后 能 满 足 循 环 终 止 条 件 而 结 束 循 环 2.do while 循 环 语 句 do while 循 环 语 句 的 语 法 形 式 为 : do // 循 环 体 部 分 while( 表 达 式 ); do while 循 环 语 句 与 while 循 环 语 句 的 区 别 在 于 :do while 循 环 语 句 首 先 执 行 循 环 体, 再 求 表 达 式 的 值, 如 果 其 值 非 0, 则 再 次 执 行 循 环 体, 直 至 表 达 式 的 值 为 零 ; 而 while 语 句 首 先 求 表 达 式 的 值, 再 按 其 值 为 零 或 非 零 决 定 是 否 执 行 循 环 体 因 此,do while 循 环 语 句 中 的 循 环 体 至 少 执 行 一 次 do while 循 环 执 行 过 程 如 图 2-5 所 示
47 38 C++ 程 序 设 计 注 意 :do while 循 环 语 句 最 后 的 分 号 不 可 缺 少 例 2.11 利 用 do while 循 环 语 句 改 写 例 2.10 循 环 体 #include"iostream.h" void main() 真 表 达 式 int i=1,sum=0; 假 do 图 2-5 do-while 循 环 执 行 过 程 sum+=i; i++; while(i<=100); cout<<"sum="<<sum<<endl; 3.for 循 环 语 句 for 循 环 语 句 的 功 能 非 常 强 大 灵 活 地 使 用 for 循 环 语 句 完 全 可 以 解 决 编 程 中 的 一 切 循 环 问 题, 所 有 while 循 环 语 句 和 do while 循 环 语 句 可 以 实 现 的 功 能, 用 for 循 环 语 句 都 可 以 实 现 for 循 环 语 句 的 语 法 形 式 为 : for( 表 达 式 1; 表 达 式 2; 表 达 式 3) 循 环 体 ; 其 中, 表 达 式 1 通 常 用 来 给 循 环 变 量 赋 初 值 ; 表 达 式 2 通 常 是 关 系 表 达 式 或 逻 辑 表 达 式, 一 般 用 来 设 置 循 环 的 条 件 ; 表 达 式 3 用 来 在 每 次 循 环 之 后 修 改 循 环 变 量 的 值 for 语 句 的 执 行 过 程 : 首 先 执 行 表 达 式 1, 给 循 环 变 量 赋 初 值 ; 接 着 执 行 表 达 式 2, 并 根 据 表 达 式 2 的 值 决 定 是 否 执 行 循 环 体, 如 果 表 达 式 2 的 值 为 true 或 其 他 非 0 值, 则 执 行 循 环 体, 否 则 退 出 循 环 ; 每 执 行 完 一 次 循 环 体 后, 再 执 行 表 达 式 3, 修 改 循 环 变 量 ; 然 后 再 执 行 表 达 式 2, 并 根 据 表 达 式 2 的 值 决 定 是 否 继 续 执 行 循 环 体 例 2.12 利 用 for 循 环 语 句 改 写 例 2.10 #include"iostream.h" void main() int i,sum=0; for(i=1; i<=100; i++) sum+=i; cout<<"sum="<<sum<<endl; 在 使 用 for 循 环 语 句 时, 应 该 注 意 下 列 几 种 情 况 (1)for 语 句 中 的 3 个 表 达 式 可 以 没 有, 但 必 须 注 意 每 个 表 达 式 后 的 分 号 不 能 省 略 此 时 for 循 环 语 句 的 形 式 为 : for(;;)
48 第 2 章 基 本 数 据 类 型 和 表 达 式 39 这 时 在 循 环 体 内 必 须 有 其 他 控 制 循 环 执 行 的 语 句, 否 则 会 形 成 死 循 环 (2) 表 达 式 1 如 果 没 有 或 不 是 用 来 给 循 环 变 量 赋 初 值, 则 应 在 for 语 句 前 给 循 环 变 量 赋 初 值 (3) 表 达 式 2 如 果 没 有, 则 在 for 语 句 循 环 体 内 应 有 其 他 控 制 循 环 执 行 的 语 句, 否 则 会 形 成 死 循 环 (4) 表 达 式 3 如 果 没 有 或 不 是 用 来 修 改 循 环 变 量 的 值, 则 应 在 for 语 句 循 环 体 内 设 置 相 应 的 语 句 例 2.13 在 屏 幕 上 显 示 0~9 共 10 个 整 数 #include"iostream.h" void main() int i=0; for(; i<=9;) cout<<i++<<'\t'; cout<<endl; 程 序 运 行 后, 将 输 出 结 果 : 转 移 语 句 C++ 语 言 还 提 供 了 goto 语 句 break 语 句 和 continue 语 句 等 转 移 语 句, 它 们 主 要 用 于 改 变 程 序 中 语 句 的 执 行 顺 序, 使 程 序 从 某 一 语 句 有 目 的 地 转 移 到 另 一 语 句 继 续 执 行 1.goto 语 句 goto 语 句 语 法 格 式 为 : goto 语 句 标 号 ; goto 语 句 的 作 用 是 使 程 序 转 移 到 语 句 标 号 所 标 示 的 语 句 处 继 续 执 行 语 句 标 号 是 一 种 用 来 标 识 语 句 的 符 号, 它 的 命 名 遵 守 C++ 语 言 对 标 识 符 的 规 定, 放 在 语 句 的 前 面, 并 用 冒 号 (:) 与 语 句 分 开 C++ 语 言 中,goto 语 句 的 使 用 被 限 制 在 一 个 函 数 体 内, 即 goto 语 句 只 能 在 一 个 函 数 范 围 内 进 行 语 句 转 移 在 同 一 函 数 中, 语 句 标 号 应 该 是 惟 一 的 必 须 指 出 的 是,C++ 语 言 中 虽 然 保 留 了 goto 语 句, 但 使 用 它 并 不 是 一 个 好 的 习 惯 事 实 上, 由 于 goto 语 句 的 使 用 会 破 坏 程 序 的 结 构, 编 程 时, 应 尽 量 少 用 或 不 用 它 当 然, 有 经 验 的 程 序 员 在 特 定 的 场 合 使 用 goto 语 句, 也 可 能 会 达 到 很 好 的 效 果 例 如, 用 goto 语 句 构 成 一 个 循 环, 程 序 如 下 : Μ int i=1,s=0; loop:i++; s+=i; if(i<=50) goto loop;
49 40 C++ 程 序 设 计 cout<<s<<endl; Μ 程 序 中 的 loop 就 是 语 句 标 号 该 语 句 也 可 以 改 写 为 : loop: i++; 这 两 种 形 式 是 等 价 的 2.break 语 句 break 语 句 的 语 法 格 式 如 下 : break; break 语 句 可 用 在 以 下 两 种 情 况 (1)break 语 句 用 在 switch 语 句 中, 其 功 能 是 退 出 switch 语 句 (2)break 语 句 用 在 循 环 语 句 的 循 环 体 中, 其 功 能 是 退 出 循 环 语 句 如 果 是 多 重 循 环, 它 将 导 致 break 语 句 所 在 的 那 重 循 环 执 行 的 结 束, 开 始 执 行 该 重 循 环 后 面 的 语 句 例 2.14 从 键 盘 上 输 入 10 个 整 数, 若 是 正 整 数 则 求 和, 若 输 入 0 则 终 止 程 序 #include"iostream.h" void main() int num,sum=0; cout<<"please input number:"<<endl; for(int i=0; i<=9;i++) cin>>num; if(num= =0) break; sum+=num; cout<<"sum="<<sum<<endl; 3.continue 语 句 continue 语 句 的 语 法 格 式 为 : continue; continue 语 句 只 能 用 在 循 环 语 句 的 循 环 体 内 在 循 环 执 行 的 过 程 中, 如 果 遇 到 continue 语 句, 程 序 将 结 束 本 次 循 环, 接 着 开 始 下 一 次 循 环 例 2.15 从 键 盘 上 输 入 10 个 整 数, 若 是 正 整 数 则 求 和 ; 若 是 负 整 数 则 不 进 行 计 算 ; 继 续 输 入 数 据, 若 输 入 0 则 终 止 程 序 #include"iostream.h" void main() int num,sum=0;
50 第 2 章 基 本 数 据 类 型 和 表 达 式 41 cout<<"please input number:"<<endl; for(int i=0; i<=9;i++) cin>>num; if(num= =0) break; if(num<0) continue; sum+=num; cout<<"sum="<<sum<<endl; 习 题 1. 判 断 下 面 的 标 识 符 是 否 合 法 Class public Xyz 7x _you union 2. 字 符 常 量 和 字 符 串 常 量 有 什 么 区 别? 3. 定 义 符 号 常 量 的 方 法 有 哪 些? 它 们 有 什 么 区 别? 4. 求 下 面 算 术 表 达 式 的 值 ( 设 x=2.5,a=7,y=4.7) (1)x+a%3*(int)(x+y)52/4 (2)(float)(a+b)/2+(int)x%(int)y (3)a++/6 (4)++a/6 (5)a++%6 (6)int(x+2) 5. 下 面 的 表 达 式 是 什 么 类 型 的 表 达 式? (1)(x+3)>4 (2)x&&y>=z (3)x+y z 6. 求 下 面 逻 辑 表 达 式 的 值 ( 设 a=3,b=4,c=5) (1)a+b>c&&b= =c (2)a b+c&&b-c (3)!(a+b)+c-1&&b+c/2 7. 分 析 下 面 程 序 的 运 行 结 果 #include"iostream.h" void main() int i=0; while(++i) if(i= =10) break; if(i%3!=1) continue; cout<<i<<endl; 8. 分 析 下 面 程 序 的 运 行 结 果 #include"iostream.h" void main()
51 42 C++ 程 序 设 计 int x=5; do switch(x%2) case 1:x--;break; case 0:x++;break; x--; cout<<x<<endl; while(x>0) 9. 编 程 求 100 以 内 的 自 然 数 中 奇 数 之 和 10. 编 程 求 100 以 内 能 被 13 整 除 的 最 大 自 然 数 11. 有 一 个 函 数 如 下 所 示 : x y = x + 5 x 5 ( x< (1 ( x> 1) x 10) 10) 编 程 实 现 从 键 盘 输 入 一 个 x, 求 出 相 应 的 y 值 12. 编 程 实 现 输 入 3 个 整 型 数, 按 由 大 到 小 的 顺 序 输 出 显 示
52 第 3 章 函 数 函 数 是 C++ 程 序 设 计 中 具 有 独 立 功 能 的 一 段 程 序, 是 C++ 程 序 的 主 要 组 成 部 分, 也 是 构 成 C++ 程 序 的 基 本 单 位 函 数 的 出 现 使 得 程 序 具 有 了 模 块 化 的 特 性 它 封 装 了 一 些 程 序 代 码 和 数 据, 实 现 了 更 高 级 的 抽 象, 使 程 序 设 计 人 员 的 主 要 精 力 从 具 体 的 实 现 细 节 转 到 函 数 的 接 口 函 数 的 工 作 方 式 在 很 大 程 度 上 决 定 C++ 程 序 的 效 率 可 读 性 和 可 移 植 性 函 数 必 须 先 说 明, 后 调 用 3.1 函 数 的 定 义 函 数 定 义 函 数 定 义 就 是 描 述 一 个 函 数 所 完 成 的 功 能,C++ 语 言 中 的 所 有 函 数 在 使 用 之 前 都 必 须 定 义 函 数 定 义 的 一 般 语 法 格 式 如 下 : 函 数 类 型 函 数 名 ( 参 数 列 表 ) 函 数 体 函 数 名 必 须 符 合 C++ 标 识 符 命 名 规 则 函 数 类 型 规 定 了 函 数 返 回 值 的 数 据 类 型, 它 可 以 是 各 种 数 据 类 型, 包 括 基 本 数 据 类 型 和 构 造 数 据 类 型, 也 包 括 指 针 和 引 用 类 型 如 果 函 数 无 返 回 值, 则 该 函 数 的 数 据 类 型 为 void 例 如 : int sum(int a,int b) // 有 返 回 值, 返 回 类 型 为 整 型 return (a+b); void printsum(int a,int b) // 无 返 回 值 cout<<a+b<<endl; 参 数 列 表 指 明 了 函 数 的 参 数 个 数 名 称 和 数 据 类 型 当 函 数 有 多 个 参 数 时, 每 个 变 量 必 须 分 别 定 义 类 型 和 名 字, 用 逗 号 将 多 个 参 数 分 开 无 参 数 时, 最 好 用 关 键 字 void 说 明 此 函 数 无 参 数, 也 可 以 不 提 供 参 数, 但 括 号 不 可 以 省 略 例 如 : int fac(int a) // 有 参 数
53 44 C++ 程 序 设 计 int i,f=1; for(i=2;i<a;i++) f*=i; return f; int max(int a,int b) // 有 参 数 return a>b?a:b; void print(void) // 无 参 数 cout<<"c++ is easy to learn!"<<endl; void print() // 无 参 数 cout<<"hello world!"<<endl; 下 面 的 函 数 说 明 方 法 是 错 误 的 : int max(int a,b) 参 数 列 表 中 的 参 数 称 为 形 式 参 数, 简 称 形 参 形 参 在 该 函 数 调 用 时 才 被 初 始 化, 从 主 调 函 数 获 取 数 据 如 果 被 调 用 函 数 不 需 要 从 调 用 函 数 那 里 获 取 数 据, 则 该 函 数 参 数 为 空 或 为 void 类 型 函 数 定 义 中 的 一 对 花 括 号 不 能 省 略, 它 用 于 指 明 函 数 体 的 开 始 和 结 束 花 括 号 内 的 函 数 体 由 语 句 组 成, 用 于 描 述 函 数 所 要 执 行 的 操 作 当 函 数 有 返 回 值 时, 在 函 数 体 中 至 少 有 一 个 return 语 句 函 数 原 型 C++ 最 重 要 的 特 征 之 一 是 函 数 原 型 函 数 原 型 告 诉 编 译 器 函 数 名 称 函 数 的 返 回 类 型 函 数 要 接 收 的 参 数 个 数 参 数 类 型 和 参 数 顺 序, 编 译 器 用 函 数 原 型 验 证 函 数 调 用 在 定 义 C++ 函 数 之 前 常 用 函 数 原 型 加 以 说 明 函 数 原 型 通 常 位 于 程 序 代 码 的 开 始 处 函 数 原 型 的 说 明 语 法 格 式 为 : 类 型 函 数 名 ( 参 数 列 表 ); 参 数 列 表 与 函 数 定 义 中 的 参 数 列 表 中 的 类 型 相 同 参 数 列 表 是 用 逗 号 隔 开 的 一 个 类 型 说 明, 其 个 数 顺 序 和 指 定 的 类 型 必 须 和 函 数 定 义 中 的 参 数 个 数 顺 序 和 类 型 一 致 例 如 : int fac(int); int sum(int,int); 在 函 数 原 型 说 明 中 也 可 以 给 出 参 数 名 例 如 : int fac(int a);
54 第 3 章 函 数 45 int max(int a,int b); 3.2 函 数 调 用 一 个 函 数 被 定 义 就 是 为 了 将 来 使 用 它 调 用 函 数 是 实 现 函 数 功 能 的 手 段 C++ 中 包 含 传 值 调 用 传 址 调 用 和 引 用 调 用 函 数 调 用 的 概 念 函 数 调 用 是 用 一 个 表 达 式 来 表 示 的 其 调 用 的 格 式 为 : 函 数 名 ( 实 参 列 表 ) 其 中, 函 数 名 是 用 户 自 定 义 的 或 是 C++ 提 供 的 标 准 函 数 名 实 参 列 表 是 由 逗 号 分 隔 的 若 干 个 表 达 式, 每 个 表 达 式 的 值 为 实 参, 实 参 是 用 来 在 调 用 函 数 时 对 形 参 进 行 初 始 化 的 实 参 与 形 参 个 数 相 同 类 型 一 致 且 顺 序 一 致 如 果 在 一 个 文 件 中 有 多 个 函 数, 一 般 都 将 主 程 序 或 主 函 数 放 在 其 他 所 有 函 数 的 前 面 在 函 数 调 用 前 进 行 函 数 原 型 的 说 明, 被 调 用 函 数 的 定 义 放 在 后 面 函 数 调 用 是 一 种 表 达 式, 这 里 的 括 号 可 以 理 解 为 函 数 调 用 运 算 符 函 数 调 用 表 达 式 的 值 是 函 数 的 返 回 值, 其 类 型 是 函 数 类 型 通 常 使 用 函 数 调 用 的 返 回 值 来 给 某 个 变 量 赋 值 函 数 的 返 回 值 是 在 被 调 用 函 数 中, 通 过 返 回 语 句 return 来 实 现 的 返 回 语 句 return 有 两 个 重 要 的 作 用 : 其 一 是 使 函 数 立 即 返 回 到 其 主 调 程 序, 其 二 是 返 回 某 个 值 函 数 有 两 种 返 回 情 况, 一 种 是 无 返 回 值, 一 种 是 有 返 回 值 当 函 数 无 返 回 值 时, 函 数 类 型 必 须 用 关 键 字 void 加 以 说 明 例 如 : void print(int a,int b); // 无 返 回 值 在 无 返 回 值 的 函 数 体 中 可 以 没 有 return 语 句, 函 数 执 行 到 函 数 体 的 最 后 一 条 语 句, 遇 到 花 括 号 时, 返 回 到 主 调 用 程 序 函 数 体 中 有 return 语 句, 但 return 后 无 表 达 式, 函 数 执 行 到 return 时, 将 返 回 到 主 调 用 程 序 例 如 : void printsum(int a,int b) // 无 返 回 值 cout<<a+b<<endl; return; 若 在 C++ 函 数 定 义 时 没 有 加 返 回 类 型, 则 C++ 函 数 返 回 值 的 缺 省 类 型 为 int, 否 则 必 须 规 定 返 回 值 的 类 型 例 如 : sum(int a,int b) // 没 有 写 返 回 类 型, 则 返 回 类 型 为 整 型 int mul(int a,int b) // 有 返 回 类 型, 返 回 类 型 为 整 型 如 果 在 函 数 定 义 时 需 要 返 回 某 个 数 值, 则 return 语 句 后 必 须 有 表 达 式 当 程 序 执 行 到 函 数 体 的 return 语 句 时, 把 return 后 面 的 表 达 式 的 值 带 给 主 调 函 数, 同 时 程 序 执 行 顺 序 返 回 到 主 调 用 程 序 中 调 用 函 数 的 下 一 条 语 句 如 果 表 达 式 的 类 型 与 函 数 的 类 型 不 相 同 时, 将 表 达 式 的 类 型 自 动 转 换 为 函 数 的 类 型, 这 种 转 换 是 强 制 的, 可 以 出 现 不 保 值 的 情 况
55 46 C++ 程 序 设 计 在 任 何 情 况 下,C++ 能 自 动 将 变 量 的 类 型 转 换 为 与 参 数 一 致 的 类 型, 这 是 C++ 标 准 类 型 转 换 的 一 部 分 例 如, 如 果 函 数 中 定 义 了 参 数 的 类 型 是 int, 可 以 用 char 类 型 的 变 量 调 用 该 函 数, C++ 会 自 动 将 char 型 数 值 转 换 成 int 型 数 值 任 何 非 法 的 转 换 都 会 被 C++ 编 译 程 序 检 测 出 来 例 3.1 实 现 两 个 数 相 加 #include "iostream.h" int add(int,int); void main() int sum,x,y; cout<<" 请 输 入 被 加 数 和 加 数 :"<<endl; cin>>x>>y; sum=add(x,y); cout<<"sum="<<sum<<endl; // 函 数 定 义 int add(int a,int b) return a+b; 执 行 结 果 : 请 输 入 被 加 数 和 加 数 : Sum=838 Press any key to continue 函 数 调 用 的 参 数 传 递 C++ 向 调 用 函 数 传 递 参 数 的 方 法 有 : 传 值 调 用 传 址 调 用 和 引 用 调 用 1. 传 值 调 用 这 种 方 法 是 用 参 数 传 递 数 据 的 最 常 用 的 方 法 调 用 函 数 的 实 参 用 常 量 变 量 或 表 达 式 的 值, 被 调 用 函 数 的 形 参 用 变 量 调 用 时 系 统 先 计 算 实 参 表 达 式 的 值, 再 把 实 参 的 值 按 位 置 赋 给 对 应 的 形 式 参 数, 即 对 形 参 进 行 初 始 化, 然 后 执 行 函 数 体 由 于 传 值 调 用 的 实 现 机 制 是 系 统 将 实 参 拷 贝 一 个 副 本 给 形 参, 因 此, 在 函 数 体 执 行 过 程 中 形 式 参 数 的 变 化 不 会 影 响 对 应 实 参 的 值 传 值 方 式 可 以 有 效 地 防 止 被 调 用 函 数 改 变 参 数 的 原 始 值, 例 3.2 展 示 出 了 向 函 数 传 值 的 过 程, 并 将 两 个 整 型 数 互 换 例 3.2 两 整 型 数 互 换 #include "iostream.h" void swap(int,int); void main()
56 第 3 章 函 数 47 int a,b; cin>>a>>b; swap(a,b); cout<<"main program a="<<a<<"\t b="<<b<<"\n"; // 函 数 定 义 void swap(int a,int b) int t; cout<<"function swap begin a="<<a<<"\t b="<<b<<"\n"; t=a; a=b; b=t; cout<<"function swap end a="<<a<<"\t b="<<b<<"\n"; 程 序 执 行 结 果 为 : function swap begin a=10 b=20 function swap end a=20 b=10 main program a=10 b=20 Press any key to continue 在 例 3.2 中, 主 函 数 调 用 函 数 swap() 时, 实 参 数 的 值 赋 给 相 应 的 形 式 参 数 在 函 数 swap() 中 进 行 两 数 交 换 后, 形 式 参 数 的 值 已 经 改 变 了, 即 函 数 swap() 将 两 个 整 型 数 互 换 但 是 由 执 行 结 果 可 以 看 出, 主 函 数 中 的 实 参 数 的 值 并 没 有 改 变 2. 传 址 调 用 使 用 传 址 调 用 方 式 时, 形 参 是 指 针 变 量, 实 参 数 是 数 据 的 地 址 值, 由 主 调 程 序 向 被 调 用 函 数 传 递 的 是 指 向 参 数 的 指 针 在 函 数 调 用 时, 把 实 参 数 地 址 赋 给 形 式 参 数, 形 式 参 数 和 实 参 数 都 使 用 同 一 地 址 中 的 值 因 此, 形 式 参 数 的 任 何 改 变 都 会 导 致 实 参 数 值 的 改 变 例 3.3 两 整 型 数 互 换 #include "iostream.h" void swap(int *,int *); // 函 数 声 明 或 函 数 原 型 void main() int a,b; cin>>a>>b; swap(&a,&b); cout<<"main program a="<<a<<"\t b="<<b<<"\n"; // 函 数 定 义
57 48 C++ 程 序 设 计 void swap(int *a,int *b) int t; cout<<"function swap begin *a="<<*a<<"\t *b="<<*b<<"\n"; t=*a; *a=*b; *b=t; cout<<"function swap end *a="<<*a<<"\t *b="<<*b<<"\n"; 程 序 执 行 结 果 为 : function swap begin *a=10 *b=20 function swap end *a=20 *b=10 main program a=20 b=10 Press any key to continue 由 例 3.3 可 以 看 出, 变 量 a 和 b 的 值 在 调 用 函 数 swap() 后 已 经 发 生 了 变 化, 真 正 实 现 了 将 两 个 整 型 数 互 换 原 因 在 于 向 函 数 传 递 地 址 ( 指 针 ) 时, 它 所 指 向 的 对 象 有 可 能 被 函 数 修 改 因 此, 使 用 地 址 ( 指 针 ) 时 必 须 谨 慎, 否 则 很 容 易 出 现 一 些 意 想 不 到 的 结 果 3. 引 用 调 用 引 用 也 是 一 种 特 殊 类 型 的 变 量, 它 不 同 于 指 针 引 用 是 在 程 序 中 为 一 个 变 量 取 一 个 别 名, 以 便 在 不 同 的 情 况 下 也 能 使 用 例 如, 可 以 为 一 个 整 型 变 量 x 取 一 个 别 名 y, 则 称 y 是 对 x 的 引 用 定 义 完 引 用 后, 在 程 序 中 对 y 的 使 用 就 像 对 x 的 使 用 一 样 定 义 引 用 的 格 式 为 : 数 据 类 型 & 引 用 名 ( 变 量 名 ); 或 者 数 据 类 型 & 引 用 名 = 变 量 名 ; 其 中 & 为 引 用 操 作 符 一 般 情 况 下, 定 义 引 用 时 必 须 初 始 化 例 如 : int x; int &y=x; 此 例 为 整 型 变 量 x 取 一 个 别 名 y,y 称 为 对 x 的 引 用,x 称 为 y 的 引 用 对 象 引 用 主 要 用 来 作 为 函 数 的 参 数 和 返 回 值 的 类 型, 将 引 用 用 作 函 数 形 参 的 作 用 与 指 针 作 为 函 数 形 参 的 作 用 是 相 同 的, 可 以 通 过 调 用 函 数 来 改 变 实 参 的 值 例 3.4 通 过 引 用 调 用 实 现 两 整 型 数 互 换 #include "iostream.h" void swap(int &,int &); void main() int a,b; cin>>a>>b;
58 第 3 章 函 数 49 swap(a,b); cout<<"main program a="<<a<<"\t b="<<b<<"\n"; // 函 数 定 义 void swap(int &x,int &y) int t; cout<<"function swap begin x="<<x<<"\t y="<<y<<"\n"; t=x; x=y; y=t; cout<<"function swap end x="<<x<<"\t y="<<y<<"\n"; 程 序 执 行 结 果 为 : function swap begin x=10 y=20 function swap end x=20 y=10 main program a=20 b=10 Press any key to continue 在 例 3.4 中, 形 参 a 和 b 是 两 个 整 型 变 量 的 引 用 函 数 被 调 用 时, 实 际 上 使 用 的 是 主 程 序 中 的 实 参 数 a 和 b 的 地 址 在 C++ 中, 将 引 用 作 为 函 数 形 参 可 以 使 用 户 程 序 更 加 简 明 对 于 函 数 的 一 个 或 多 个 参 数,C++ 程 序 用 引 用 调 用 取 代 传 值 调 用 使 用 引 用 参 数 时, 变 量 的 地 址 将 自 动 传 给 函 数 在 函 数 体 内, 对 引 用 进 行 的 操 作 由 系 统 自 动 实 现 因 此, 一 旦 在 定 义 函 数 时 定 义 了 引 用 调 用, 在 函 数 体 内 就 没 有 必 要 再 使 用 指 针 操 作 符 * 函 数 的 嵌 套 调 用 和 递 归 调 用 1. 函 数 的 嵌 套 调 用 程 序 从 主 函 数 开 始 执 行, 遇 到 函 数 调 用 时, 如 果 函 数 是 有 参 函 数,C++ 先 进 行 实 参 对 形 参 的 替 换, 然 后 执 行 被 调 用 函 数 的 函 数 体 如 果 函 数 体 中 还 调 用 其 他 函 数, 再 转 入 执 行 其 他 函 数 体 函 数 体 执 行 完 毕 后, 返 回 到 主 调 函 数, 继 续 执 行 主 调 函 数 中 的 后 续 程 序 行 若 在 一 个 函 数 中 又 调 用 另 一 个 函 数, 则 称 这 样 的 调 用 过 程 为 函 数 的 嵌 套 调 用 例 3.5 函 数 的 嵌 套 调 用 #include "iostream.h" void f1(); void f2(); void f3(); int max(int,int); void main()
59 50 C++ 程 序 设 计 cout<<"1 main program begin "<<endl; int a; f1(); a=max(2,10); cout<<"8 max number is:"<<a<<endl; cout<<"9 main program end "<<endl; // 函 数 f1 定 义 void f1() cout<<"2 function f1 begin "<<endl; fa2(); cout<<"6 function f1 end "<<endl; //function af void f2() cout<<"3 function f2 begin "<<endl; f3(); cout<<"5 function f2 end "<<endl; //function a3 void f3() cout<<"4 function f3 begin "<<endl; //function max int max(int a,int b) int x; x=(a>b? a:b); cout<<"7 function max "<<endl; return x; 执 行 结 果 如 下 : 1 main program begin 2 function f1 begin 3 function f2 begin 4 function f3 begin
60 第 3 章 函 数 51 5 function f2 end 6 function f1 end 7 function max 8 max number is:10 9 main program end Press any key to continue 2. 函 数 的 递 归 调 用 在 调 用 一 个 函 数 的 过 程 中 出 现 直 接 或 间 接 调 用 该 函 数 本 身 的 情 形, 就 称 作 函 数 的 递 归 调 用 这 样 的 函 数 称 为 递 归 函 数 编 写 递 归 函 数 时, 必 须 有 终 止 递 归 调 用 的 条 件 例 3.6 用 递 归 求 阶 乘 1 n! = n( n 1)! n = 1 n > 1 #include "iostream.h" int fac(int n); void main() int n; cout<<"input a integer number:"; cin>>n; cout<<n<<"!="<<fac(n)<<endl; int fac(int n) if(n==1)return 1; else return n*fac(n 1); 执 行 结 果 如 下 : Input a integer number:8 8!=40320 Press any key to continue 首 先, 主 函 数 main() 调 用 函 数 fac(n), 此 时 n=8; 由 于 8!=1, 函 数 fac(n) 再 用 n-1=7 作 为 参 数 调 用 它 本 身, 此 时 7!=1; 接 下 来, 用 n=6 调 用 函 数 fac(n); 不 断 重 复 此 过 程, 直 到 用 1 调 用 函 数 fac (1), 然 后 函 数 fac(1) 返 回 由 于 函 数 fac(1) 返 回 到 其 调 用 点, 所 以, 程 序 执 行 前 一 次 动 作 的 语 句 2*1, 这 样 函 数 fac(n) 返 回 到 其 前 一 次 调 用 点, 故 返 回 2; 返 回 过 程 不 断 进 行, 直 到 所 有 调 用 都 返 回, 程 序 结 束 例 3.7 Hanoi( 汉 诺 ) 塔 游 戏 有 3 根 针 A,B 和 C, 开 始 时 A 针 上 有 n 个 盘 子, 盘 子 大 小 不 等, 大 的 在 下, 小 的 在 上 要 求 把 这 n 个 盘 子 从 A 针 移 动 到 C 针, 规 则 是 每 次 只 允 许 移 动 一 个 盘 子, 只 能 在 A,B 和 C 三 个 针 上 移 动, 在 移 动 过 程 中 不 允 许 出 现 大 盘 子 压 在 小 盘 子 上 的
61 52 C++ 程 序 设 计 情 形 编 程 实 现 移 动 的 步 骤 这 是 一 个 典 型 的 用 递 归 方 法 求 解 的 例 子 将 n 个 盘 子 从 A 针 移 动 到 C 针 可 以 分 解 成 以 下 3 个 步 骤 (1) 将 A 上 的 n-1 个 盘 子 借 助 C 针 移 动 到 B 针 上 (2) 把 A 上 的 最 后 的 1 个 盘 子 移 到 C 针 上 (3) 将 B 上 的 n-1 个 盘 子 借 助 A 针 移 动 到 C 针 上 将 一 个 盘 子 从 一 根 针 上 移 动 到 另 一 根 针 上, 可 以 用 函 数 move(char source,char dest) 表 示, 用 hanoi(int n,char one,char two,char three) 表 示 将 n 个 盘 子 从 one 针 移 动 到 three 针 上, 中 间 借 助 于 two 针 程 序 如 下 : #include "iostream.h" void move(char sour,char dest); void hanoi(int n,char one,char two,char three); void main() int n; cout<<"input the number diskes:"; cin>>n; hanoi(n,'a','b','c'); void move(char sour,char dest) cout<<"move from "<<sour<<" to "<<dest<<endl; void hanoi(int n,char one,char two,char three) if(n==1) move(one,three); else hanoi(n 1,one,three,two); move(one,three); hanoi(n 1,two,one,three); 程 序 执 行 结 果 为 : Input the number diskes:4 Move from A to B Move from A to C
62 第 3 章 函 数 53 Move from B to C Move from A to B Move from C to A Move from C to B Move from A to B Move from A to C Move from B to C Move from B to A Move from C to A Move from B to C Move from A to B Move from A to C Move from B to C Press any key to continue 函 数 main() 的 参 数 许 多 程 序 在 运 行 时 都 允 许 带 有 命 令 行 参 数 命 令 行 参 数 是 指 那 些 跟 在 执 行 程 序 后 面 且 位 于 操 作 系 统 所 要 求 的 命 令 行 上 的 参 数, 其 作 用 是 把 某 些 信 息 传 递 给 程 序 命 令 行 的 一 般 形 式 为 : 命 令 名 参 数 1 参 数 2 参 数 n C++ 程 序 中 允 许 使 用 命 令 行 参 数 C++ 程 序 通 过 将 两 个 参 数 传 递 给 mani() 函 数, 达 到 控 制 程 序 的 目 的 这 两 个 参 数 分 别 是 argc 和 argv, 是 可 选 项, 当 然, 命 令 行 参 数 在 不 用 时 可 以 省 略 参 数 argc 用 来 存 放 命 令 行 参 数 的 数 量, 它 是 一 个 整 型 数 由 于 程 序 名 被 当 作 第 一 个 参 数, 所 以 argc 的 值 至 少 为 1 参 数 argv 是 一 个 字 符 串 指 针 数 组, 定 义 argv 的 最 常 用 方 法 为 : char *argv[ ]; argv 右 侧 的 方 括 号 [ ] 说 明 该 数 组 不 是 定 长 数 组 所 有 命 令 行 参 数 都 被 当 作 字 符 串 传 递 给 main() 函 数 在 主 程 序 体 中, 参 数 argv 通 过 加 下 标 来 接 收 不 同 的 字 符 串 例 如, 用 argv[0] 指 向 程 序 名,argv[1] 指 向 程 序 名 后 的 第 一 个 参 数 下 面 的 程 序 实 现 了 在 DOS 提 示 符 下 输 入 带 参 数 的 可 执 行 文 件 名, 并 在 屏 幕 上 输 出 显 示 它 的 参 数 例 3.8 使 用 命 令 行 参 数 //test.cpp #include "stdafx.h" #include "iostream.h" int main(int argc, char* argv[]) while(argc>1)
63 54 C++ 程 序 设 计 ++argv; cout<<*argv<<endl; argc--; return 0; 运 行 例 3.8 程 序 时, 当 输 入 命 令 行 为 test Beijing Shanghai Tianjin Chongqing 时,argc=5, argv[0]= test,argv[1]= Beijing,argv[2]= Shanghai,argv[3]= Tianjin,argv[4]= Chongqing 输 出 为 : Beijing Shanghai Tianjin Chongqing 参 数 名 argc 和 argv 是 任 意 的, 编 程 人 员 可 以 定 义 自 己 的 参 数 名,argc 和 argv 只 不 过 是 一 种 习 惯 的 用 法 最 好 的 命 名 方 法 是 让 阅 读 程 序 的 人 能 够 根 据 参 数 名 立 即 判 断 出 它 在 程 序 中 所 起 的 作 用 3.3 局 部 变 量 和 全 局 变 量 作 用 域 是 用 来 说 明 数 据 的 使 用 范 围 的 一 个 变 量 的 作 用 域 是 程 序 中 的 一 段 区 域, 用 于 确 定 该 变 量 的 可 见 性 按 作 用 域 的 大 小 可 以 把 变 量 分 为 局 部 变 量 和 全 局 变 量 局 部 变 量 在 函 数 或 者 类 内 说 明 的 变 量 是 局 部 变 量 局 部 变 量 仅 在 定 义 它 的 函 数 或 类 内 起 作 用, 在 这 个 范 围 之 外 不 能 使 用 这 些 变 量 局 部 变 量 的 作 用 域 也 称 为 块 作 用 域 函 数 内 部 使 用 的 局 部 变 量 包 括 形 式 参 数 和 函 数 体 内 定 义 的 变 量 函 数 的 形 式 参 数 的 作 用 域 在 函 数 的 函 数 体 内 部 不 同 函 数 如 果 使 用 相 同 的 参 数 或 变 量, 它 们 仅 在 其 所 在 函 数 体 内 有 效, 互 不 影 响 在 函 数 体 内 定 义 的 变 量, 其 作 用 域 从 说 明 语 句 开 始 直 到 该 函 数 结 束 为 止 函 数 外 部 的 变 量 在 函 数 内 部 是 不 可 见 的 全 局 变 量 全 局 变 量 是 在 函 数 和 类 外 部 定 义 的 变 量 全 局 变 量 的 作 用 域 从 说 明 点 开 始 直 到 文 件 的 结 束 这 种 作 用 域 也 称 为 文 件 作 用 域 全 局 变 量 一 般 集 中 在 主 函 数 之 前 说 明, 它 提 供 了 各 个 函 数 之 间 联 系 的 一 种 方 法 利 用 全 局 变 量 可 以 减 少 参 数 数 量 和 数 据 传 递 时 间 但 是, 过 多 的 全 局 变 量 会 降 低 程 序 的 通 用 性 和 程 序 的 可 读 性, 并 且 全 局 变 量 在 程 序 运 行 过 程 中 始 终 占 用 内 存, 所 以 应 尽 量 减 少 使 用 全 局 变 量 好 的 程 序 设 计 方 法 是 用 函 数 交 换 信 息 应 使 用 参 数 和 返 回 值, 而 不 使 用 全 局 变 量 如 果 全 局 变 量 与 函 数 的 局 部 变 量 同 名, 在 函 数 的 局 部 变 量 的 作 用 域 内, 同 名 的 全 局 变 量 无 效 为 了 在 函
64 第 3 章 函 数 55 数 体 内 使 用 与 局 部 变 量 同 名 的 全 局 变 量, 应 在 全 局 变 量 前 面 使 用 作 用 域 作 用 符 :: 例 3.9 全 局 变 量 和 局 部 变 量 的 使 用 #include "iostream.h" int i=3; void main() double i=2.2; cout<<"local variable i is "<<i<<"\n"; cout<<"glocal variable i is "<<::i<<"\n"; 程 序 执 行 结 果 为 : local variable i is 2.2 glocal variable i is 3 Press any key to continue 3.4 内 联 函 数 函 数 调 用 是 将 程 序 执 行 顺 序 转 移 到 函 数 所 存 放 在 内 存 中 的 某 个 地 址, 将 函 数 的 程 序 执 行 完 后, 再 返 回 到 调 用 该 函 数 前 的 地 方 这 种 转 移 操 作 要 求 转 移 前 保 护 现 场 并 记 住 转 移 点 的 地 址, 转 回 来 后 还 要 恢 复 现 场, 并 按 原 来 保 存 的 地 址 继 续 执 行 因 此, 函 数 调 用 要 有 一 定 的 时 间 和 空 间 方 面 的 开 销, 将 影 响 程 序 的 执 行 效 率 特 别 是 对 于 一 些 函 数 体 代 码 较 少, 但 又 频 繁 被 调 用 的 函 数 来 讲, 解 决 其 效 率 问 题 更 为 重 要 引 入 内 联 函 数 的 目 的 是 为 了 解 决 函 数 调 用 的 效 率 问 题 在 程 序 编 译 时, 编 译 器 将 程 序 中 出 现 的 内 联 函 数 的 调 用 表 达 式 用 内 联 函 数 的 函 数 体 进 行 替 换 使 用 内 联 函 数, 加 快 了 程 序 的 执 行 速 度, 但 如 果 函 数 体 中 的 语 句 很 多, 则 会 增 加 程 序 代 码 的 长 度 由 于 C++ 编 译 程 序 必 须 知 道 内 联 函 数 的 函 数 体, 才 能 进 行 内 联 替 换, 因 此, 内 联 函 数 必 须 在 程 序 中 第 一 次 调 用 此 函 数 的 语 句 前 通 知 C++ 编 译 程 序 在 C++ 中, 除 了 带 有 循 环 语 句 switch 语 句 的 函 数 不 能 被 说 明 为 内 联 函 数 外, 其 他 函 数 都 可 以 被 说 明 为 内 联 函 数 内 联 函 数 的 定 义 形 式 为 : inline 类 型 函 数 名 ( 形 式 参 数 列 表 ); 例 3.10 使 用 内 联 函 数 的 方 法, 判 断 从 键 盘 输 入 的 字 符 是 字 母 还 是 数 字 #include "iostream.h" inline int isnumber(char c) return (c>='0'&&c<='9')? 1:0; void main() char c;
65 56 C++ 程 序 设 计 cout<<"enter a character:"; cin>>c; if(isnumber(c)) cout<<"you entered a digit\n"; else cout<<"you entered a character\n"; 程 序 执 行 结 果 为 : Enter a character:2 you entered a digit Press any key to continue 另 一 种 执 行 结 果 为 : Enter a character:a you entered a character Press any key to continue 3.5 函 数 重 载 函 数 重 载 是 指 同 一 个 函 数 名 可 以 对 应 着 多 个 不 同 函 数 的 实 现 例 如, 可 以 给 函 数 名 sum( ) 定 义 多 个 函 数 实 现, 该 函 数 的 功 能 是 求 3 个 操 作 数 的 和 其 中, 一 个 函 数 实 现 的 是 求 3 个 int 型 整 数 之 和, 另 一 个 实 现 的 是 求 3 个 double 型 浮 点 数 之 和, 再 一 个 实 现 的 是 求 3 个 复 数 之 和 每 种 实 现 对 应 着 一 个 函 数 体, 这 些 函 数 的 名 字 相 同, 但 是 函 数 的 参 数 的 类 型 不 同 这 是 函 数 重 载 的 概 念 函 数 重 载 要 求 编 译 器 能 够 惟 一 地 确 定 调 用 一 个 函 数 时 应 执 行 哪 个 函 数 代 码 确 定 函 数 时, 编 译 器 是 通 过 函 数 的 参 数 个 数 参 数 类 型 和 参 数 顺 序 来 区 分 的 也 就 是 说, 进 行 函 数 重 载 时, 要 求 同 名 函 数 参 数 个 数 不 同 参 数 类 型 不 同 或 参 数 顺 序 不 同, 否 则 将 无 法 确 定 是 哪 一 个 函 数 体 注 意, 函 数 的 返 回 类 型 不 能 区 分 不 同 的 函 数 体 例 3.11 求 三 个 操 作 数 之 和 #include "iostream.h" int sum(int,int,int); double sum(double,double,double); void main() cout<<"int:"<<sum(2,3,4)<<endl; cout<<"double:"<<sum(1.4,2.7,3.8)<<endl; int sum(int a,int b,int c) return a+b+c;
66 第 3 章 函 数 57 double sum(double a,double b,double c) return a+b+c; 程 序 执 行 结 果 为 : Int:9 Double:7.9 Press any key to continue 例 3.12 求 几 个 操 作 数 中 的 最 大 者 #include "iostream.h" int max(int,int); int max(int,int,int); void main() cout<<"max2:"<<max(22,38)<<endl; cout<<"max3:"<<max(4,72,18)<<endl; int max(int a,int b) return a>b?a:b; int max(int a,int b,int c) return max(a,b)?max(a,b):c; 程 序 执 行 结 果 为 : Max2:38 Max3:72 Press any key to continue 习 题 1. 在 C++ 中, 函 数 定 义 的 格 式 是 怎 样 的? 2. 什 么 是 函 数 的 声 明? 函 数 声 明 和 函 数 定 义 有 什 么 区 别? 函 数 的 声 明 是 否 必 需? 3. 函 数 的 传 值 调 用 传 址 调 用 和 引 用 调 用 各 有 何 特 点? 4. 什 么 是 內 联 函 数? 引 入 內 联 函 数 的 目 的 是 什 么? 5. 什 么 是 函 数 重 载? 函 数 重 载 的 原 则 是 什 么? 6. 函 数 的 嵌 套 调 用 应 注 意 什 么?
67 58 C++ 程 序 设 计 7. 函 数 的 递 归 调 用 有 什 么 特 点? 8. 什 么 是 局 部 变 量? 什 么 是 全 局 变 量? 9. 在 C++ 中, 如 何 使 用 系 统 函 数? 10. 分 析 下 列 程 序 的 输 出 结 果 (1) #include "iostream.h" #define N 8 void fun(int); void main() for(int i=1;i<n;i++) fun(i); void fun(int x ) int a=0,b=2; cout<<(a+=x+3,a+b)<<endl; (2) #include "iostream.h" const int N=5; void fun(); int a=0; void main() for(int i=1;i<n;i++) fun(); void fun() int b=2; cout<<(a+=3,a+b)<<endl; (3) #include "iostream.h" int sum(int a,int b); void main() extern int x,y;
68 cout<<sum(x,y)<<endl; int x(10),y(15); int sum(int a,int b) int z=a+b; return z; (4) #include "iostream.h" #include "string.h" void reverse(char *str); void main() char me[]="ok"; reverse(me); cout<<me<<endl; void reverse(char *as_a) int i,j; char ch,str[10]; if(!*as_a) return; for(i=0,j=strlen(as_a) 1;i<j;i++,j--) ch=str[i]; str[i]=str[j]; str[j]=ch; (5) #include "iostream.h" int gcd(int,int); void main() int a,b; a=16;b=24; cout<< "GCD("<<a<<','<<b<<")="<<gcd(a,b)<<endl; 第 3 章 函 数 59
69 60 C++ 程 序 设 计 int gcd(int a,int b) if(b==0)return a; else return gcd(b,a%b); 11. 从 键 盘 输 入 10 个 浮 点 数, 求 其 和 及 其 平 均 值 要 求 写 出 其 和 及 平 均 值 的 函 数 12. 给 定 某 年 月 日 的 值, 计 算 这 一 天 是 该 年 的 第 几 天 要 求 写 出 计 算 闰 年 的 函 数 和 计 算 日 期 的 函 数 13. 写 出 一 个 函 数, 使 从 键 盘 输 入 的 一 个 字 符 串 反 序 存 放, 并 在 主 函 数 中 输 入 输 出 该 字 符 串 14. 写 一 个 函 数, 要 求 将 从 键 盘 输 入 的 十 进 制 整 数 转 换 成 二 进 制 数 15. 用 递 归 方 法 将 一 个 n 位 整 数 转 换 成 字 符 串 16. 用 递 归 和 非 递 归 方 法 计 算 菲 波 那 切 数 列 的 前 20 项 菲 波 那 切 数 列 前 两 项 是 1, 从 第 三 项 起, 每 一 项 是 前 两 项 数 据 之 和, 即 1,1,2,3,5,8,13,
70 第 4 章 数 组 在 C++ 中, 数 组 是 最 简 单 的 用 户 自 定 义 数 据 类 型, 所 有 的 数 据 类 型 都 可 以 用 于 一 维 或 多 维 数 组, 其 维 数 在 定 义 时 确 定 一 个 数 组 包 含 同 一 种 数 据 类 型 的 多 个 变 量 实 例, 通 常 把 这 些 变 量 称 为 数 组 元 素, 访 问 数 组 元 素 需 要 利 用 整 型 的 下 标 表 达 式 4.1 一 维 数 组 的 定 义 和 数 组 元 素 的 引 用 一 维 数 组 的 定 义 把 若 干 个 同 类 型 的 数 据 线 性 地 组 合 在 一 起, 就 构 成 一 维 数 组 在 使 用 一 维 数 组 之 前 必 须 先 定 义, 在 定 义 的 部 分 要 说 明 数 组 的 数 据 类 型 数 组 名 和 数 组 元 素 的 个 数 定 义 一 维 数 组 的 一 般 格 式 为 : < 数 据 类 型 > < 数 组 名 >[n] 例 如 :int A[100] 表 示 数 组 名 为 A, 该 数 组 有 100 个 元 素, 数 组 元 素 的 类 型 为 整 型 在 定 义 一 维 数 组 时 要 注 意 以 下 几 点 (1) 数 据 类 型 一 般 指 的 是 该 数 组 元 素 的 类 型 (2) 数 组 名 的 命 名 规 则 要 遵 循 C++ 关 于 标 识 符 的 命 名 规 则 (3) 数 组 的 元 素 个 数 就 是 数 组 长 度, 例 如 A[100] 中 100 表 示 100 个 元 素 用 A[0],A[1],, A[99] 分 别 表 示 这 100 个 元 素, 方 括 号 中 的 0,1,,99 是 数 组 的 下 标 如 果 有 n 个 元 素, 则 下 标 是 从 0 到 n-1 注 意 : 数 组 长 度 是 用 方 括 号 括 起 来 的 一 个 整 数, 不 能 用 圆 括 号 例 如,int A(100) 的 意 思 是 定 义 了 一 个 整 型 变 量 A, 并 赋 予 初 值 为 100, 并 不 是 定 义 了 一 个 数 组 A (4) 必 须 要 说 明 数 组 的 长 度, 且 这 个 长 度 要 用 一 个 确 定 的 正 整 数 来 表 示 例 如 :int a[]; // 不 合 法, 没 有 定 义 数 组 的 长 度 ; int x; int a[x]; // 不 合 法, 不 能 用 一 个 变 量 定 义 数 组 的 长 度 (5) 一 次 也 可 以 说 明 多 个 同 类 型 数 组 例 如 :int a[10],b[15],c[20]; // 定 义 a,b,c3 个 整 型 数 组 一 维 数 组 的 初 始 化 数 组 同 变 量 一 样 需 要 初 始 化, 数 组 的 初 始 化 可 采 用 以 下 几 种 方 法 实 现
71 62 C++ 程 序 设 计 (1) 同 基 本 类 型 的 变 量 一 样, 可 以 在 定 义 数 组 的 同 时 对 其 进 行 初 始 化 例 如,int a[4]=1,2,3,4 语 句 不 仅 定 义 了 一 个 一 维 数 组, 同 时 将 它 的 4 个 元 素 分 别 进 行 初 始 化, 即 a[0]=1,a[1]=2,a[2]=3,a[3]=4 (2) 在 定 义 数 组 时 既 可 以 对 所 有 元 素 进 行 初 始 化, 也 可 以 只 对 其 中 的 一 部 分 元 素 进 行 初 始 化 例 如 :int a[4]=7,8 语 句 对 数 组 a 中 的 元 素 a[0],a[1] 赋 值, 即 a[0]=7,a[1]=8, 其 余 数 组 元 素 的 值 都 默 认 为 0 (3) 要 使 一 个 数 组 中 全 部 元 素 的 值 为 0, 可 以 有 如 下 定 义 方 法 : int a[4]= ; int a[4]=0,0,0,0; int a[4]=0; (4) 全 部 数 组 元 素 赋 初 始 值 时, 可 以 不 指 定 数 组 长 度 计 算 机 会 根 据 初 始 化 的 数 组 元 素 的 个 数 自 动 分 配 存 储 空 间 例 如,int a[ ]=1,2,3,4,5 语 句 表 示 数 组 的 长 度 为 5 (5) 利 用 for 循 环 语 句 赋 初 始 值 例 如 :for(int i=0;i<100;i++) a[i]=i+1; 一 维 数 组 元 素 的 引 用 数 组 元 素 引 用 的 格 式 为 : 数 组 名 [ 下 标 ] 其 中, 下 标 可 以 是 整 型 常 量 或 整 型 表 达 式 例 如 :a[8]=a[1+1]+a[3] a[2*2] 例 4.1 求 出 一 个 数 组 a[8], 使 a[i] 的 值 为 下 标 值 的 平 方, 然 后 按 逆 序 输 出 #include"iostream.h" void main() int i,a[8]; for (i=0;i<=7;i++) a[i]=i*i; // 利 用 for 语 句 给 每 个 数 组 元 素 赋 初 值 for (i=7;i>=0;i--) cout<<a[i]<<" "; // 利 用 下 标, 对 数 组 元 素 进 行 引 用 cout<<endl; 运 行 结 果 如 下 : 一 维 数 组 的 使 用 数 组 必 须 先 定 义 后 使 用 例 4.2 从 键 盘 上 输 入 任 意 4 个 整 数 赋 给 数 组, 显 示 该 数 组, 最 后 计 算 并 显 示 该 数 组 的 累
72 第 4 章 数 组 63 加 和 与 平 均 值 #include"iostream.h" void main() int a[4],i,sum=0; // 声 明 数 组 和 变 量 double avg; for (i=0;i<4;i++) cout<<"a["<<i<<"]="; // 利 用 for 语 句 给 数 组 赋 值 cin>>a[i]; // 直 接 显 示 数 组 元 素 cout<<a[0]<<" "<<a[1]<<" "<<a[2]<<" "<<a[3]<<" "<<endl; for (i=0;i<4;i++) // 利 用 for 循 环 显 示 数 组 元 素 的 值 cout<<a[i]<<" "; cout<<endl; sum=a[0]+a[1]+a[2]+a[3]; // 计 算 数 组 元 素 之 和, 并 显 示 计 算 结 果 cout<<"sum="<<sum<<endl; sum=0; for (i=0;i<4;i++) sum=a[i]+sum; // 利 用 for 语 句 求 出 和 cout<<"sum="<<sum<<endl; avg=sum/4.0; cout<<"avg="<<avg<<endl; 运 行 结 果 为 : a[0]=1 a[1]=3 a[2]=5 a[3]= sum=16 sum=16 avg=4 例 4.3 一 个 数 恰 好 等 于 它 的 因 子 之 和, 这 个 数 就 称 为 完 全 数 例 如 6 的 因 子 是 1,2, 3, 而 6=1+2+3, 因 此 6 是 完 全 数 编 程 找 出 所 输 入 数 值 范 围 内 的 所 有 完 全 数, 并 输 出 其 各 因 子 #include"iostream.h" void main()
73 64 C++ 程 序 设 计 int k[40]; // 定 义 一 个 整 型 的 一 维 数 组, 数 组 名 为 k, 元 素 的 个 数 为 40 int i,j,s,m,n; cout<<" 请 输 入 要 寻 找 完 全 数 的 范 围 :"; cin>>m; for (j=2;j<=m;j++) n=0; s=j; for (i=1;i<j;i++) if((j%i)==0) n++; s=s i; k[n]=i; // 给 数 组 元 素 赋 值 if(s==0) cout<<j<<" 是 一 个 完 全 数, 它 的 因 子 是 :"; for(i=1;i<=n;i++) cout<<k[i]<<" "; // 利 用 for 语 句 引 用 数 组 元 素 cout<<endl; 运 行 程 序, 输 出 结 果 如 下 : 请 输 入 要 寻 找 完 全 数 的 范 围 : 是 一 个 完 全 数, 它 的 因 子 是 : 是 一 个 完 全 数, 它 的 因 子 是 : 是 一 个 完 全 数, 它 的 因 子 是 : 二 维 数 组 的 定 义 和 数 组 元 素 的 引 用 二 维 数 组 的 定 义 二 维 数 组 在 定 义 时 也 要 说 明 数 组 的 数 据 类 型 数 组 名 和 数 组 元 素 的 个 数 二 维 数 组 定 义 的 一 般 形 式 为 :
74 第 4 章 数 组 65 < 数 组 类 型 > < 数 组 名 >[m][n] 例 如 :int a[4][3] 就 定 义 了 一 个 二 维 数 组 a, 其 数 据 元 素 为 a[0][0],a[0][1],a[4][3] 怎 样 理 解 二 维 数 组 呢?C++ 语 言 对 二 维 数 组 采 用 这 样 的 定 义 方 a[0] a00 a01 a02 式, 使 我 们 可 以 把 二 维 数 组 看 作 是 一 种 特 殊 的 一 维 数 组, 它 的 元 素 又 a[1] a10 a11 a12 是 一 个 一 维 数 组 例 如, 可 以 把 a[4][3] 看 作 是 一 个 一 维 数 组, 它 有 4 a[2] a20 a21 a22 个 元 素 :a[0],a[1],a[2],a[3], 每 个 元 素 又 是 一 个 包 含 3 个 元 素 的 a[3] a30 a31 a32 一 维 数 组, 如 图 4-1 所 示 图 4-1 二 维 数 组 示 例 C++ 这 种 处 理 数 组 的 方 法, 在 数 组 初 始 化 和 用 指 针 表 示 时 会 很 方 便 在 C++ 中, 二 维 数 组 是 按 行 的 顺 序 存 储 的 按 行 的 顺 序 存 储 即 在 内 存 中 先 存 储 第 一 行, 接 着 存 储 第 二 行, 其 他 行 依 次 类 推 二 维 数 组 元 素 的 初 始 化 二 维 数 组 元 素 的 初 始 化 方 法 很 多, 常 用 的 有 以 下 几 种 方 法 (1) 对 二 维 数 组 元 素 赋 初 值, 以 每 行 为 一 组 例 如 :int a[4][3]=0,1,2,3,4,5,6,7,8,9,10,11; 显 而 易 见, 这 种 方 法 比 较 直 观, 即 把 第 一 个 花 括 号 内 的 数 据 赋 给 第 一 行 的 元 素, 第 二 个 花 括 号 内 的 数 据 赋 给 第 二 行 的 元 素,, 依 此 类 推 (2) 所 有 的 数 据 写 在 一 个 花 括 号 内, 根 据 数 组 排 列 的 顺 序 以 及 数 组 的 行 数 和 列 数, 计 算 机 会 自 动 给 各 数 组 元 素 赋 初 值 例 如,int a[3][4]=0,1,2,3,4,5,6,7,8,9,10,11, 则 a[1][2]=5 例 如,int a[4][3]=0,1,2,3,4,5,6,7,8,9,10,11, 则 a[3][2]=11 很 明 显, 方 法 (1) 一 行 对 一 行, 界 限 清 楚 ; 方 法 (2) 如 果 数 据 过 多, 数 据 很 容 易 遗 漏 和 增 加, 不 易 检 查 (3) 可 以 只 给 部 分 数 组 元 素 赋 初 始 值 例 如,a[4][3]=1,5,6,7 语 句 的 作 用 是 只 对 每 行 第 一 列 的 数 组 元 素 赋 初 值, 其 余 元 素 为 0, 即 a[0][0]=1,a[1][0]=5,a[2][0]=6,a[3][0]=7, 数 组 a 的 数 据 元 素 如 图 4-2 所 示 需 要 注 意 的 是, 给 部 分 元 素 赋 初 值 时, 最 好 用 第 一 种 方 法 如 果 用 第 二 种 方 法 赋 初 始 值 a[4][3]=1,5,6,7, 则 a[0][0]=1,a[0][1]=5,a[0][2]=6,a[0][3]=7, 其 余 的 元 素 默 认 为 (4) 可 以 对 某 一 行 中 的 某 一 元 素 赋 初 值, 也 可 以 对 某 一 行 不 进 行 赋 值 例 如,int a[4][3]=0,1,,0,0,2,0,1 语 句 使 得 a[0][0]=0,a[0][1]=1, 图 4-2 部 分 数 组 元 素 赋 初 始 值 a[0][2]=0,a[1][0]=a[1][1]=a[1][2]=0,a[2][0]=a[2][1]=0,a[2][2]=2,a[3][0]=a[3] [2]=0,a[3][1]=1 这 种 方 法 经 常 用 于 数 组 元 素 中 0 比 较 多 的 情 况 (5) 如 果 对 全 部 数 组 元 素 赋 初 始 值, 则 定 义 数 组 时 第 一 维 的 长 度 可 以 不 指 定, 但 第 二 维 的 长 度 不 能 省 略 例 如,int a[2][3]=1,2,3,4,5,6 可 以 写 成 int a[ ][3]=1,2,3,4,5,6 例 4.4 定 义 一 个 4 行 3 列 的 整 数 数 组, 并 使 a[3][2]=6,a[0][2]=7, 其 余 的 元 素 为 0, 数 组 名 为 a 根 据 题 意, 数 组 定 义 如 下 :
75 66 C++ 程 序 设 计 int a[][3]=0,0,7,,,0,0,6 (6) 二 维 数 组 的 元 素 赋 初 始 值, 可 用 二 重 循 环 语 句 例 如 : for(int i=0;i<4;i++) for(int j=0;j<4;j++) a[i][j]=i+j; 二 维 数 组 元 素 的 引 用 引 用 二 维 数 组 元 素 的 格 式 为 : < 数 组 名 > [< 行 下 标 >][< 列 下 标 >] 例 如 :int a[2][3] 定 义 了 一 个 2 行 3 列 的 整 数 数 组, 如 引 用 其 中 的 第 2 行 第 1 列 元 素, 应 写 为 a[1][0] 二 维 数 组 的 上 标 和 下 标 可 以 是 整 数 常 量 或 整 型 表 达 式 如 果 行 下 标 为 m, 列 下 标 为 n, 则 该 二 维 数 组 共 包 含 m*n 个 数 组 元 素 其 中 行 下 标 最 大 值 为 m-1, 列 下 标 最 大 值 为 n-1 注 意 : (1) 不 要 把 int a[3][2] 写 成 int a[3,2] (2) 下 标 值 要 在 已 定 义 的 数 组 的 最 大 范 围 内, 即 不 要 越 界 例 如,int a[4][3] 定 义 了 一 个 4 行 3 列 的 一 个 整 数 数 组 a, 如 果 定 义 a[4][3]=6, 则 下 标 越 界 二 维 数 组 的 使 用 例 4.5 定 义 一 个 二 维 数 组 a[2][2], 对 它 进 行 初 始 化, 并 输 出 所 有 的 初 始 值 求 出 a[0][1]+a [1][0] #include"iostream.h" void main() int a[2][2]=23,34,45,67; for(int i=0;i<2;i++) for(int j=0;j<2;j++) cout<<a[i][j]<<" "; cout<<endl; int sum; sum=a[0][1]+a[1][0]; cout<<" a[0][1]+a[1][0]="<<sum<<endl; 程 序 执 行 的 结 果 为 : a[0][1]+a[1][0]=79 例 4.6 编 写 程 序 将 给 定 的 一 个 二 维 数 组 (m*n) 转 置 并 输 出 #include"iostream.h"
76 第 4 章 数 组 67 const int n=3; const int m=4; int a[m][n],b[n][m]; // 定 义 两 个 二 维 数 组 void fun(int a[m][n],int b[n][m]); // 数 组 为 函 数 的 形 参 void main() int i,j; cout<<" 请 输 入 a 数 组 元 素 的 值 :"<<endl; for (i=0;i<m;i++) for (j=0;j<n;j++) cin>>a[i][j]; // 利 用 二 重 循 环 对 二 维 数 组 a 的 元 素 进 行 赋 值 cout<<" 输 入 的 数 组 a 是 :"<<endl; for (i=0;i<m;i++) for (j=0;j<n;j++) cout<<" "<<a[i][j]<<" "; // 利 用 二 重 循 环 引 用 二 维 数 组 a 的 元 素 cout<<endl; fun (a,b); // 数 组 为 函 数 的 实 参 时, 只 要 写 上 数 组 的 名 字 cout<<" 转 置 后 的 数 组 b 是 :"<<endl; for (i=0;i<n;i++) for (j=0;j<m;j++) cout<<" "<<b[i][j]<<" "; cout<<endl; void fun (int a[m][n], int b[n][m]) for (int i=0;i<m;i++) for (int j=0;j<n;j++) // 利 用 二 重 循 环 对 二 维 数 组 b 的 元 素 进 行 赋 值 b[j][i]=a[i][j]; 运 行 程 序, 输 出 结 果 为 : 请 输 入 a 数 组 元 素 的 值 : 输 入 的 数 组 a 为 :
77 68 C++ 程 序 设 计 转 置 后 的 数 组 b 为 : 字 符 数 组 字 符 数 组 的 定 义 及 初 始 化 字 符 数 组 是 数 据 类 型 为 字 符 类 型 的 数 组, 它 用 来 存 放 字 符 型 数 据, 其 中 每 一 个 数 组 元 素 对 应 一 个 字 符 字 符 数 组 定 义 的 格 式 为 : char 数 组 名 [n]; 例 如 :char c [10] 语 句 定 义 了 一 个 可 以 存 放 10 个 字 符 的 字 符 数 组 字 符 数 组 的 初 始 化 一 般 有 如 下 两 种 方 法 (1) 逐 个 字 符 赋 给 数 组 中 的 元 素 例 4.7 逐 个 字 符 初 始 化 字 符 数 组 #include"iostream.h" void main() // 逐 个 字 符 对 字 符 数 组 初 始 化 char a[13]='h','e','l','l','o',',','w','o','r','l','d','!'; cout<<a<<endl; // 把 字 符 数 组 作 为 整 体 进 行 输 出, 直 到 遇 到 '\0' cout<<a[10]<<endl; // 输 出 字 符 数 组 的 一 个 元 素 运 行 程 序, 输 出 结 果 为 : Hello,World! d 注 意 : 如 果 花 括 号 中 提 供 的 初 值 字 符 个 数 大 于 数 组 长 度, 则 作 语 法 错 误 处 理 ; 如 果 初 值 个 数 小 于 数 组 长 度, 则 多 余 的 数 组 元 素 自 动 定 义 为 字 符 串 结 束 符 ' \0' (2) 对 整 个 字 符 数 组 赋 初 值 例 4.8 对 整 个 字 符 数 组 赋 初 值 #include"iostream.h" void main() char a[13]="hello,world!"; cout<<a<<endl; cout<<a[10]<<endl;
78 第 4 章 数 组 69 程 序 的 结 果 如 下 : Hello,World! d 可 以 看 出, 例 4.8 和 例 4.7 输 出 结 果 相 同 字 符 数 组 Hello,World! 共 有 12 个 字 符, 但 数 组 长 度 定 义 为 13, 原 因 在 于 字 符 串 常 量 的 最 后 由 系 统 加 上 了 一 个 '\0' 字 符, 表 示 字 符 串 的 结 束 字 符 串 处 理 函 数 1.strcat(string1, string2) strcat 函 数 的 功 能 是 实 现 将 两 个 字 符 数 组 中 的 字 符 串 连 接 起 来, 即 把 string2 连 接 到 string1 的 后 面, 并 将 结 果 存 到 string1 中 例 4.9 strcat 函 数 应 用 举 例 #include"iostream.h" #include"string.h" void main() char a[10]= "Beijing"; char b[20]= "Shanghai"; char c[10]= "and"; strcat(a,c); strcat(a,b); cout<<a; cout<<end1; strcat(b,c); strcat(b,a); cout<<b; cout<<end1; 运 行 程 序, 输 出 结 果 为 : Beijing and Shanghai Shanghai and Beijing and Shanghai 应 该 注 意 的 是, 两 个 字 符 数 组 连 接 后, 则 前 一 个 数 组 的 结 束 字 符 '\0' 消 失 了 另 外 要 注 意 的 是 存 放 结 果 字 符 数 组 的 空 间 要 足 够 大 2.strcpy(string1, string2) strcpy 函 数 的 功 能 是 将 string2 中 的 字 符 复 制 到 string1 中 去 复 制 的 时 候, 连 同 string2 后 面 的 '\0' 一 起 复 制, 且 要 求 string1 中 必 须 有 存 储 字 符 数 组 string2 中 所 有 字 符 的 空 间,string2 可 以 是 一 个 字 符 数 组 名, 也 可 以 是 一 个 字 符 串 常 量 例 4.10 strcpy 函 数 应 用 举 例 #include"iostream.h"
79 70 C++ 程 序 设 计 #include"string.h" void main() char a[10],b[ ]= "Hello1! "; strcpy(a,b) //string1 和 string2 是 字 符 数 组 名 cout<<a<<end1; strcpy(a, "hello2! "); //string1 是 字 符 数 组 名,string2 是 一 个 字 符 串 常 量 cout<<a<<end1; 运 行 程 序, 输 出 结 果 为 : Hello1! Hello2! 3.strcmp(string1, string2) strcmp 函 数 的 功 能 是 比 较 string1 和 string2 比 较 的 规 则 为 : 两 个 字 符 串 自 左 至 右 逐 个 比 较 ( 按 ASCII 码 值 大 小 比 较 ), 直 到 出 现 不 同 的 字 符 或 遇 到 '\0' 为 止 如 全 部 字 符 相 同, 则 认 为 相 等 ; 若 出 现 不 相 同 的 字 符, 则 以 第 一 个 不 相 同 的 字 符 的 比 较 结 果 为 准, 比 较 的 结 果 由 函 数 值 带 回 (1) 如 果 字 符 串 1= 字 符 串 2, 函 数 值 为 0; (2) 如 果 字 符 串 1> 字 符 串 2, 函 数 值 为 1; (3) 如 果 字 符 串 1< 字 符 串 2, 函 数 值 为 1 例 4.11 strcmp 函 数 应 用 举 例 #include"iostream.h" #include"string.h" void main() int s1,s2,s3; s1=strcmp("china","russia"); s2=strcmp("china","china"); s3=strcmp("chinaf","chinae"); cout<<"s1="<<s1<<endl; cout<<"s2="<<s2<<endl; cout<<"s3="<<s3<<endl; 程 序 执 行 的 结 果 为 : s1= 1 s2=0 s3=1 需 要 注 意 的 是, 两 个 字 符 串 比 较 只 能 用 strcmp 函 数, 不 能 用 下 面 的 语 句 : if(str1= =str2) cout<<"ok"; 该 语 句 可 以 改 写 为 :if(strcmp(str1,str2)= =0) cout<<"ok"
80 第 4 章 数 组 71 4.strlen( 字 符 数 组 ) strlen 函 数 的 功 能 是 测 试 字 符 串 的 长 度, 函 数 值 为 字 符 串 实 际 的 长 度, 不 包 括 '\0' 在 内 例 如 : char str[10]= "Good"; cout<<strlen(str)<<end; 则 输 出 结 果 为 5, 不 是 6, 也 不 是 10 但 是 cout<<sizeof(str)<<end1;, 则 输 出 的 结 果 为 10 因 为 sizeof(x) 函 数 是 测 试 计 算 机 为 该 变 量 x 实 际 分 配 的 内 存 空 间 的 大 小 字 符 数 组 的 应 用 例 4.12 计 算 一 个 字 符 串 ( 无 空 格 ) 中 字 符 的 个 数 #include"iostream.h" #include"string.h" void main() char a[100]; cin>>a; char *pt=a; int i; for(i=0;*pt!='\0';++pt) ++i; cout<<" 这 一 串 字 符 中 共 有 "<<i<<" 个 字 符 "<<endl; 例 4.13 编 程 求 出 一 个 二 维 字 符 数 组 里 元 素 为 'a' 的 个 数 #include"iostream.h" #include"string.h" void reada(char a[5][4]); void main() char a[5][4]; int i,j,number=0; reada(a); for(i=0;i<5;i++) for(j=0;j<4;j++) if(a[i][j]!='a') continue; number++; cout<<" 这 个 字 符 串 中 有 :"<<number<<" 个 a"<<endl;
81 72 C++ 程 序 设 计 void reada(char a[5][4]) int i,j; cout<<" 请 输 入 字 符 串 :"<<endl; for(i=0;i<5;i++) for(j=0;j<4;j++) cin>>a[i][j]; 程 序 的 执 行 结 果 为 : 请 输 入 字 符 串 : sfdsgfaahsfyhsfdahdg 这 个 字 符 串 中 有 :3 个 a 习 题 1. 定 义 一 个 整 型 的 一 维 数 组, 并 将 各 数 组 元 素 都 赋 值 为 该 数 组 下 标 值 的 2 倍 2. 定 义 一 个 整 型 的 二 维 数 组, 每 个 数 组 元 素 的 赋 值 规 则 为 : 行 下 标 值 加 上 列 下 标 值 3. 定 义 一 个 整 型 的 二 维 数 组, 要 求 使 用 二 重 循 环 将 每 个 数 组 元 素 都 赋 值 为 2 4. 将 年 月 日 转 换 为 当 年 的 第 几 天 5. 统 计 输 入 字 符 串 中 数 字 字 母 和 其 他 字 符 的 个 数 6. 从 键 盘 上 任 意 输 入 15 个 数, 找 出 其 中 的 最 大 数 及 其 位 置 7. 从 键 盘 上 任 意 输 入 15 个 数, 按 照 从 大 到 小 的 顺 序 输 出 8. 编 写 程 序 找 出 输 入 的 一 个 二 维 数 组 (a*b) 的 马 鞍 点 并 输 出 马 鞍 点 指 的 是 在 数 值 上 某 行 最 大 元 素 同 时 是 某 列 最 少 元 素 9. 从 键 盘 上 任 意 输 入 15 个 小 写 字 母, 变 成 大 写 字 母 后 按 反 序 输 出 10.Erarosthenes 法 求 100 以 内 的 所 有 素 数, 按 从 小 到 大 的 顺 序 依 次 排 列 Erarosthenes 法 : 1 不 是 素 数, 去 掉 它 ;2 是 素 数, 则 它 的 倍 数 不 是 素 数, 去 掉 它 们 ;3 是 素 数, 则 它 的 倍 数 不 是 素 数, 去 掉 它 们, 依 次 类 推, 直 到 所 给 定 的 数 11. 求 斐 波 那 契 数 列 中 前 40 个 元 素 的 值 斐 波 那 契 数 列 就 是 可 以 把 它 表 示 为 F0,F1,F2,, 但 是 F0 和 F1 以 外, 其 他 元 素 的 值 都 是 它 们 前 两 个 元 素 值 之 和, 即 Fn=Fn-2+Fn-1, 而 F0 和 F1 分 别 为 0 和 编 程 实 现 魔 方 阵 即 N*N(N 为 奇 数 ) 个 自 然 数 填 入 方 阵 中, 使 它 的 每 行 每 列 及 对 角 线 的 数 之 和 为 N (N N+1)/2 如 N=3 时, 则 为 : 自 定 义 函 数 strcmp, 实 现 两 个 字 符 串 的 比 较
82 第 4 章 数 组 打 印 如 下 图 形 ***** ***** ***** ***** 世 纪 法 国 数 学 家 加 斯 巾 的 一 本 数 学 的 游 戏 问 题 描 述 了 许 多 有 趣 问 题, 约 瑟 问 题 就 是 其 中 之 一 15 名 基 督 教 和 15 名 异 教 徒 同 乘 一 船 航 行, 途 中 风 浪 大 作, 危 急 万 分, 领 航 者 告 诉 大 家, 只 要 将 全 船 的 一 半 人 投 入 海 中, 其 余 人 就 能 幸 免 大 家 都 赞 成 这 个 办 法, 并 协 定 这 30 人 围 成 一 圈, 由 第 7 人 起 报 数, 每 数 至 第 9 人 便 把 他 投 入 海 中, 下 一 个 接 着 从 1 开 始 报 数, 第 9 个 人 又 被 投 入 海 中, 依 次 循 环, 直 到 剩 下 15 人 为 止 问 如 何 排 法 让 被 投 入 海 中 的 人 全 为 异 教 徒?
83 第 5 章 结 构 体 和 共 用 体 为 了 求 解 较 复 杂 的 问 题,C++ 语 言 提 供 了 一 种 用 户 自 定 义 数 据 类 型 的 机 制, 利 用 该 机 制 可 以 定 义 较 复 杂 的 数 据 类 型, 如 数 组 结 构 体 和 共 用 体 但 是 这 些 复 杂 数 据 类 型 的 元 素 或 成 员 的 数 据 类 型 仍 然 是 基 本 数 据 类 型, 故 又 把 这 些 用 户 自 己 定 义 的 复 杂 数 据 类 型 称 为 构 造 数 据 类 型 5.1 结 构 体 C++ 语 言 中 的 基 本 数 据 类 型 只 能 用 来 描 述 简 单 的 数 据, 如 可 用 整 型 描 述 学 生 的 年 龄, 用 字 符 串 型 ( 即 字 符 指 针 或 字 符 数 组 ) 描 述 学 生 的 姓 名, 用 浮 点 型 描 述 学 生 的 成 绩 等 但 是 在 处 理 实 际 问 题 时, 经 常 会 遇 到 复 杂 的 数 据 结 构, 它 可 能 包 含 一 个 或 多 个 数 据 项, 每 个 数 据 项 的 含 义 不 同, 各 数 据 项 可 以 具 有 不 同 的 数 据 类 型, 并 且 需 要 将 多 种 不 同 类 型 的 数 据 组 合 成 一 个 有 机 的 整 体 以 便 引 用 当 然, 这 些 不 同 的 数 据 之 间 是 相 互 联 系 的 例 如, 描 述 学 生 这 个 实 体, 可 以 有 学 号 姓 名 性 别 数 学 成 绩 英 语 成 绩 和 语 文 成 绩 等 属 性 这 些 属 性 都 与 学 生 有 联 系, 是 一 个 相 互 关 联 的 整 体, 都 用 来 说 明 学 生 这 个 实 体 但 这 些 属 性 的 含 义 及 数 据 类 型 都 不 相 同, 无 法 用 基 本 数 据 类 型 进 行 整 体 描 述, 如 果 把 这 些 属 性 定 义 成 相 互 独 立 的 简 单 变 量, 又 很 难 反 映 出 它 们 之 间 的 内 在 联 系 在 计 算 机 中 要 描 述 学 生 实 体, 就 必 然 要 描 述 这 些 属 性 那 么 用 数 组 可 以 描 述 这 些 属 性 吗? 答 案 是 否 定 的 原 因 在 于 数 组 要 求 所 有 的 数 据 元 素 必 须 是 同 一 数 据 类 型, 而 学 生 这 个 实 体 的 属 性 是 一 些 不 同 类 型 的 量, 如 学 号 可 以 是 长 整 型, 姓 名 性 别 可 以 是 字 符 型, 各 门 课 程 的 成 绩 可 以 是 实 型 等 因 此, 要 描 述 学 生 实 体, 数 组 是 无 能 为 力 的, 必 须 使 用 另 外 一 种 数 据 类 型, 这 就 是 结 构 体 (struct) 结 构 体 是 一 种 非 常 有 用 的 数 据 类 型, 也 是 今 后 学 习 类 类 型 的 基 础 结 构 体 成 员 组 合 在 一 起 形 成 一 个 整 体, 结 构 体 中 的 成 员 可 以 是 不 同 的 类 型, 就 相 当 于 数 据 库 中 的 记 录 定 义 结 构 体 之 后, 可 以 用 结 构 体 定 义 多 个 这 种 类 型 的 实 体, 称 为 结 构 体 变 量 结 构 体 的 定 义 结 构 体 定 义 的 一 般 语 法 形 式 为 : struct 结 构 体 名 数 据 类 型 成 员 1; 数 据 类 型 成 员 2;
84 第 5 章 结 构 体 和 共 用 体 75 数 据 类 型 成 员 n; ; 其 中,struct 是 定 义 结 构 体 类 型 的 关 键 字 结 构 体 名 由 用 户 自 行 命 名, 只 要 符 合 C++ 语 言 的 标 识 符 命 名 规 则 即 可 花 括 号 内 是 组 成 该 结 构 体 的 各 个 成 员, 结 构 体 成 员 可 以 是 变 量 数 组 或 指 针 在 结 构 体 的 定 义 中 要 对 每 个 成 员 的 成 员 名 和 数 据 类 型 进 行 说 明 每 个 成 员 的 数 据 类 型 可 以 是 基 本 数 据 类 型, 也 可 以 是 已 经 定 义 过 的 结 构 体 注 意 : 定 义 结 构 体 时, 最 后 的 分 号 不 可 缺 少 例 如 : struct student // 定 义 名 为 student( 学 生 ) 的 结 构 体 long number; // 学 号 char name[10]; // 姓 名 char sex; // 性 别 float shuxue; // 数 学 float yingyu; // 英 语 float yuwen; // 语 文 ; 结 构 体 变 量 的 定 义 结 构 体 是 一 种 特 殊 的 数 据 类 型, 它 和 基 本 数 据 类 型 int,float 和 double 等 一 样, 用 户 可 以 利 用 结 构 体 来 定 义 结 构 体 变 量, 所 不 同 的 是 每 一 种 基 本 数 据 类 型 只 有 一 种 例 如, 整 型 就 是 int 型, 单 精 度 型 就 是 float 型, 双 精 度 型 就 是 double 型 等, 而 结 构 体 可 以 有 很 多 种,student( 学 生 ) 只 是 其 中 一 种, 还 可 以 定 义 person( 人 ) employee( 职 工 ) 等 许 多 结 构 体 结 构 体 的 定 义 仅 仅 是 给 出 了 该 结 构 体 的 组 成 情 况, 系 统 并 不 为 其 分 配 实 际 的 存 储 单 元, 为 了 使 用 它, 必 须 定 义 结 构 体 变 量 例 如 : struct student zhangfan,liying; 上 面 的 语 句 定 义 了 student 型 结 构 体 变 量 zhangfan( 张 帆 ) 和 liying( 李 英 ) 此 时, 编 译 器 会 按 结 构 体 的 组 成 为 zhangfan 和 liying 两 个 结 构 体 变 量 分 配 存 储 空 间, 存 储 空 间 的 大 小 是 结 构 体 中 各 成 员 变 量 所 占 空 间 大 小 的 总 和 其 信 息 的 格 式 和 含 义 与 结 构 体 student 相 同, 即 zhangfan 和 liying 这 两 个 结 构 体 变 量 都 包 含 有 number,name,sex,shuxue,yingyu 和 yuwen 六 个 成 员 定 义 结 构 体 变 量 可 采 用 以 下 3 种 形 式 1. 直 接 定 义 直 接 定 义 是 指 在 定 义 结 构 体 的 同 时 定 义 结 构 体 变 量 例 如 : struct worker char name[10]; // 工 人 姓 名 float salary; // 工 人 工 资 worker1,worker2; 该 例 在 定 义 结 构 体 worker 的 同 时, 定 义 了 两 个 worker 类 型 的 结 构 体 变 量 worker1 和
85 76 C++ 程 序 设 计 worker2 2. 间 接 定 义 间 接 定 义 是 指 先 定 义 结 构 体, 然 后 再 定 义 结 构 体 变 量 例 如 : struct worker char name[10]; // 工 人 姓 名 float salary; // 工 人 工 资 ; struct worker worker1,worker2; 注 意 : 在 C 语 言 中 使 用 间 接 方 式 定 义 结 构 体 变 量 时,struct 关 键 字 仍 然 要 写 ; 而 在 C++ 语 言 中 则 可 以 不 写 struct 关 键 字 3. 无 名 定 义 当 采 用 直 接 方 式 定 义 结 构 体 变 量 时, 可 以 省 略 结 构 体 名 例 如 : struct char name[10]; // 工 人 姓 名 float salary; // 工 人 工 资 worker1,worker2; 注 意 : 无 名 定 义 由 于 省 略 了 结 构 体 名, 因 此 以 后 不 能 再 用 这 种 结 构 体 类 型 定 义 其 他 结 构 体 变 量 结 构 体 变 量 的 初 始 化 在 定 义 结 构 体 变 量 的 同 时 可 以 对 结 构 体 变 量 进 行 初 始 化, 即 给 每 个 结 构 体 变 量 赋 初 值, 就 像 对 数 组 初 始 化 一 样 其 语 法 格 式 为 : struct 结 构 体 名 结 构 体 变 量 名 = 初 值 ; 其 中, 初 值 的 数 目 顺 序 和 类 型 均 应 与 定 义 结 构 体 时 成 员 的 数 目 顺 序 和 类 型 保 持 一 致 例 如 : struct student zhangfan=53101,"zhangfan",'m',86,92,93 这 里 将 zhangfan.number 初 始 化 为 53101,zhangfan.name 初 始 化 为 "zhang fan",zhangfan.sex 初 始 化 为 'm',zhangfan.shuxue 初 始 化 为 86,zhangFan.yingyu 初 始 化 为 92,zhangfan.yuwen 初 始 化 为 结 构 体 变 量 的 使 用 虽 然 结 构 体 变 量 是 作 为 一 个 整 体 被 定 义 的, 但 一 般 不 能 将 一 个 结 构 体 变 量 作 为 一 个 整 体 进 行 输 入 / 输 出, 可 以 通 过 结 构 体 变 量 的 成 员 来 访 问 它 使 用 结 构 体 变 量 的 语 法 格 式 为 : 结 构 体 变 量. 成 员 名 其 中, 符 号. 是 成 员 运 算 符, 用 于 访 问 一 个 结 构 体 变 量 中 的 某 个 结 构 体 成 员 例 如,workerl,name 表 示 workerl 结 构 体 变 量 中 的 name 成 员 对 结 构 体 中 的 成 员 可 以 像 一 般 变 量 一 样 进 行 各 种 运 算 例 如 : zhangfan.number = 53101; // 结 构 体 变 量 的 成 员 作 为 左 值 被 赋 值
86 第 5 章 结 构 体 和 共 用 体 77 ZhangFan.Sex ='m'; 除 了 上 述 对 结 构 体 变 量 取 地 址 运 算 外, 在 下 述 情 况 下 结 构 体 或 结 构 体 变 量 也 可 以 作 为 整 体 参 与 运 算 : sizeof(struct student); // 计 算 结 构 体 所 占 内 存 大 小 或 sizeof(zhangfan); // 计 算 结 构 体 变 量 所 占 内 存 大 小 zhangfan=liying; // 同 类 型 的 结 构 体 变 量 可 作 为 一 个 整 体 赋 值 例 5.1 设 计 一 个 学 生 结 构 体, 包 括 姓 名 性 别 年 龄 和 地 址 等 成 员 然 后 定 义 结 构 体 变 量 并 进 行 初 始 化, 输 出 显 示 结 果 #include"iostream.h" #include"string.h" struct student char name[10]; char sex[3]; int age; char adderss[100]; ; struct student stu1=" 李 明 "," 男 ",22, " 北 京 市 "; void main() struct student stu1=" 李 明 "," 男 ",22, " 北 京 市 "; cout<<stu1.name<<'\t'<<stu1.sex<<'\t'<<stu1.age<<'\t'<<stu1.adderss<<endl; strcpy(stu1.name," 王 芳 "); strcpy(stu1.sex," 女 "); stu1.age=20; strcpy(stu1.adderss," 天 津 市 "); cout<<stu1.name<<'\t'<<stu1.sex<<'\t'<<stu1.age<<'\t'<<stu1.adderss<<endl; 程 序 运 行 后, 输 出 结 果 为 : 李 明 男 22 北 京 市 王 芳 女 20 天 津 市 结 构 体 数 组 如 果 数 组 中 的 每 个 元 素 都 是 一 个 结 构 体 变 量, 则 称 这 样 的 数 组 为 结 构 体 数 组 1. 结 构 体 数 组 的 定 义 与 定 义 结 构 体 变 量 一 样, 结 构 体 数 组 可 以 采 用 3 种 定 义 方 式 : 直 接 定 义 间 接 定 义 和 无 名 定 义 例 如 : struct worker
87 78 C++ 程 序 设 计 char name[10]; float salary; workers[2]; // 直 接 定 义 struct worker char name[10]; float salary; ; worker workers[2]; // 间 接 定 义 struct char name[10]; float salary; workers[2]; // 无 名 定 义 与 其 他 类 型 数 组 一 样, 结 构 体 数 组 名 代 表 结 构 体 数 组 中 第 一 个 元 素 在 内 存 中 的 首 地 址, 数 组 各 元 素 在 内 存 中 按 规 则 连 续 存 放 结 构 体 数 组 每 个 元 素 代 表 一 个 结 构 体, 而 当 需 要 引 用 结 构 体 数 组 元 素 中 的 某 一 成 员 时, 可 采 用 与 结 构 体 变 量 中 引 用 结 构 体 成 员 相 同 的 方 法, 利 用. 运 算 符 来 操 作 例 如, 要 引 用 结 构 体 数 组 workers 中 的 第 2 个 元 素 workers[1] 的 成 员 name, 可 表 示 为 workers[1].name 结 构 体 数 组 元 素 的 成 员 和 普 通 变 量 一 样, 可 以 被 赋 值, 也 可 以 参 加 各 种 运 算 例 如 : strcpy(workers[1].name, "li ming"); workers[1].salary=300; 2. 结 构 体 数 组 的 初 始 化 结 构 体 数 组 初 始 化 的 一 般 形 式 为 : struct 结 构 体 名 结 构 体 数 组 名 []= 初 值 ; 例 如 : struct worker char name[10]; float salary; workers[2]="li ming",800,"liu xiang",900; 结 构 体 数 组 的 初 始 化 数 据 放 在 花 括 号 内, 每 个 数 组 元 素 的 初 值 用 括 起 来, 数 据 之 间 用 逗 号, 分 隔, 每 个 数 组 元 素 初 值 的 个 数 顺 序 和 类 型 必 须 与 其 对 应 的 结 构 体 成 员 一 致 当 然, 上 面 的 程 序 在 定 义 结 构 体 数 组 时, 也 可 以 不 给 出 结 构 体 数 组 元 素 的 个 数, 系 统 会 自 动 根 据 结 构 体 数 组 初 值 的 个 数 来 自 动 定 义 结 构 体 数 组 元 素 的 个 数 例 如 :
88 第 5 章 结 构 体 和 共 用 体 79 struct worker char name[10]; float salary; workers[ ]="li ming",800,"liu xiang",900; 例 5.2 从 键 盘 输 入 学 生 的 学 号 姓 名 以 及 3 门 课 程 的 成 绩, 保 存 到 结 构 体 数 组 中, 并 且 要 求 用 数 组 成 员 保 存 3 门 课 程 的 成 绩 和 平 均 成 绩 计 算 每 个 人 3 门 课 程 的 平 均 成 绩 #include"iostream.h" #include"stdio.h" #define n 45 struct student long number; char name[12]; float score[4]; stu[n]=0; void input(void); void caculate(void); void output(void); void main() input(); caculate(); output(); void input(void) int i; cout<<"input the number,name and scores:\n"; for(i=0;i<n;i++) cout<<i<<" number:"; cin>>stu[i].number; if(stu[i].number==0) break; // 若 输 入 的 学 号 为 0 就 结 束 输 入 cout<<" name:"; cin>>stu[i].name; cout<<" yingyu:"; cin>>stu[i].score[0]; cout<<" shuxue:";
89 80 C++ 程 序 设 计 cin>>stu[i].score[1]; cout<<" yuwen:"; cin>>stu[i].score[2]; void caculate(void) int i; for(i=0;i<n;i++) if(stu[i].number==0) break; stu[i].score[3]=(stu[i].score[0]+stu[i].score[1]+stu[i].score[2])/3; void output(void) int i; for(i=0;i<n;i++) if(stu[i].number==0) break; cout<<i<<": "<<stu[i].number<<" "<<stu[i].name<<" "<<stu[i].score[0]; cout<<" "stu[i].score[1]<<" "<<stu[i].score[2]<<" "<<stu[i].score[3]<<endl; 运 行 程 序, 输 出 结 果 为 : Input the number,name and scores: 0 number: name:zhangli yingyu:94 shuxue:85 yuwen:93 1 number: name:liufang yingyu:75 shuxue:65 yuwen:83 2 number:0 ( 结 束 输 入 ) 0: zhangli : liufang
90 第 5 章 结 构 体 和 共 用 体 81 注 : 上 面 的 程 序 中 下 划 线 部 分 表 示 键 盘 输 入, 表 示 回 车 换 行 例 5.3 在 结 构 体 数 组 中 查 找 工 资 值 最 大 的 记 录 #include"iostream.h" struct person char name[10]; bool sex; int age; float salary; ; struct person a[4]=" 李 明 ",1,22, 380," 王 强 ",1,34,560," 刘 刚 ",1,28,450," 王 霞 ",0,26,480; void output(int n) cout<<" 显 示 具 有 person 结 构 的 "<<n<<" 个 记 录 "<<endl; for(int i=0;i<n;i++) cout<<a[i].name<<' '; if(a[i].sex==true) cout<<" 男 "<<' '; else cout<<" 女 "<<' '; cout<<a[i].age<<' '<<a[i].salary<<endl; void find(int n) int k=0; //k 表 示 当 前 具 有 最 大 工 资 值 的 元 素 下 标 float x=a[0].salary; for(int i=1;i<n;i++) if(a[i].salary>x) x=a[i].salary; k=i; cout<<endl<<" 显 示 数 组 a 中 具 有 最 大 工 资 值 的 记 录 :"<<endl; cout<<a[k].name<<' '; if(a[k].sex==true)
91 82 C++ 程 序 设 计 cout<<" 男 "<<' '; else cout<<" 女 "<<' '; cout<<' '<<a[k].age<<' '<<a[k].salary<<endl; void main() output(4); find(4); 运 行 程 序, 输 出 结 果 为 : 显 示 具 有 person 结 构 的 4 个 记 录 李 明 男 王 强 男 刘 刚 男 王 霞 女 显 示 数 组 a 中 具 有 最 大 工 资 值 的 记 录 : 王 强 男 共 用 体 前 面 为 学 生 定 义 了 结 构 体 student, 同 样 也 可 以 为 教 师 定 义 结 构 体 teacher student 和 teacher 这 两 个 结 构 体 中 肯 定 有 大 部 分 的 属 性 ( 如 姓 名 性 别 及 年 龄 等 ) 是 相 同 的, 那 么 能 不 能 把 学 生 和 教 师 定 义 成 一 种 结 构 呢? 答 案 是 肯 定 的 但 是, 这 两 个 结 构 体 中 肯 定 也 会 有 些 属 性 是 不 同 的 比 如, 学 生 有 班 级 属 性, 教 师 有 职 称 属 性, 这 是 两 者 属 性 的 不 同 之 处, 所 以 这 两 种 结 构 体 并 不 完 全 相 同 怎 么 才 能 定 义 成 一 种 结 构 呢? 一 种 处 理 方 法 是 在 结 构 体 中 同 时 定 义 这 两 种 属 性, 对 学 生 来 说 职 称 属 性 空 着 不 用, 对 教 师 来 说 班 级 属 性 空 着 不 用 另 一 种 更 好 的 方 法 是 将 班 级 和 职 称 这 两 种 属 性 合 成 为 一 种 属 性, 当 表 示 学 生 信 息 时 它 是 班 级, 当 表 示 教 师 信 息 时 它 是 职 称, 要 做 到 这 一 点 就 需 用 到 共 用 体 (union) 共 用 是 指 多 种 不 同 类 型 的 变 量 从 同 一 地 址 开 始 存 放, 共 同 占 用 同 一 段 内 存 单 元 这 种 含 有 共 用 体 成 员 的 结 构 体 称 为 异 质 结 构 在 实 际 应 用 中 异 质 结 构 是 很 有 用 的, 比 如 对 某 种 产 品 的 描 述 也 会 遇 到 上 述 同 样 的 问 题, 因 为 对 所 有 产 品 来 说 其 大 多 数 属 性 可 能 都 一 样, 但 个 别 属 性 会 因 产 品 而 异, 这 时 也 要 用 到 异 质 结 构 共 用 体 同 结 构 体 一 样, 也 是 一 种 自 定 义 的 数 据 类 型, 由 若 干 数 据 成 员 组 成, 并 且 也 可 以 带 有 成 员 函 数 虽 然 共 用 体 与 结 构 体 有 很 多 相 似 之 处, 但 两 者 还 是 有 本 质 区 别 的 在 任 一 时 刻, 结 构 体 中 的 所 有 成 员 都 是 可 访 问 的, 而 共 用 体 中 只 有 一 个 成 员 可 以 访 问, 其 他 所 有 成 员 都 是 不 可 访 问 的 这 种 不 同 反 映 到 存 储 空 间 分 配 上 就 是 结 构 体 变 量 各 成 员 顺 序 存 放 在 一 段 内 存 中, 每
92 第 5 章 结 构 体 和 共 用 体 83 个 成 员 分 别 占 有 自 己 的 内 存 单 元, 结 构 体 变 量 所 占 存 储 空 间 的 大 小 等 于 其 所 有 数 据 成 员 所 占 存 储 空 间 的 总 和 而 共 用 体 变 量 的 各 成 员 均 从 同 一 地 址 开 始 存 放, 共 同 占 用 同 一 存 储 空 间, 即 各 成 员 所 占 用 的 存 储 空 间 是 相 互 覆 盖 的 因 此, 每 个 共 用 体 变 量 所 占 存 储 空 间 的 大 小 等 于 其 所 有 数 据 成 员 中 所 占 存 储 空 间 最 大 者 的 值, 在 任 一 时 刻 只 能 从 变 量 的 首 地 址 开 始 保 存 一 个 数 据 成 员 的 值 共 用 体 共 用 体 变 量 的 定 义 共 用 体 可 以 看 成 是 结 构 体 的 变 种, 其 定 义 和 使 用 方 式 都 与 结 构 体 极 其 相 似 共 用 体 共 用 体 变 量 的 定 义 形 式 为 : union 共 用 体 名 数 据 类 型 成 员 1; 数 据 类 型 成 员 2; 数 据 类 型 成 员 n 变 量 列 表 ; 例 如 : union example int x; char y; double z; a,b; 以 上 语 句 定 义 了 共 用 体 example 及 共 用 体 变 量 a 和 b,x,y 和 z 都 是 共 用 体 example 的 数 据 成 员 a 和 b 所 占 的 存 储 空 间 大 小 等 于 3 个 数 据 成 员 x,y 和 z 中 所 占 存 储 空 间 最 大 的 值, 即 max(4,1,8)=8 个 字 节, 并 且 x,y 和 z 都 是 从 同 一 地 址 开 始 存 放 任 一 时 刻 只 能 有 一 个 数 据 成 员 可 以 访 问 如 果 将 上 例 定 义 成 结 构 体, 例 如 : struct example int x; char y; double z; a,b; 则 结 构 体 变 量 a 和 b 所 占 的 存 储 空 间 大 小 等 于 3 个 数 据 成 员 x,y 和 z 中 所 占 存 储 空 间 之 和, 即 等 于 4+1+8=13 个 字 节, 其 数 据 成 员 x,y 和 z 分 别 从 不 同 的 地 址 开 始 存 放, 可 以 随 时 被 访 问 定 义 共 用 体 变 量 时, 也 可 以 将 类 型 定 义 与 变 量 定 义 分 开, 还 可 以 直 接 定 义 共 用 体 变 量 而 不 给 出 共 用 体 名, 这 一 点 和 定 义 结 构 体 变 量 完 全 相 同 如 上 例 中 定 义 共 用 体 变 量 a 和 b 也 可 以 写
93 84 C++ 程 序 设 计 为 : example a,b; 共 用 体 和 结 构 体 在 变 量 的 初 始 化 上 也 有 所 不 同 系 统 允 许 对 结 构 体 中 的 每 个 数 据 成 员 按 照 定 义 的 次 序 进 行 初 始 化, 但 对 共 用 体 来 说 只 允 许 对 其 第 一 个 成 员 进 行 初 始 化, 而 不 允 许 初 始 化 其 他 成 员 共 用 体 变 量 的 使 用 共 用 体 变 量 的 使 用 方 式 与 结 构 体 相 同, 也 不 能 将 一 个 共 用 型 变 量 作 为 一 个 整 体 进 行 输 入 / 输 出, 只 能 通 过 共 用 体 变 量 的 成 员 来 访 问 它 成 员 访 问 仍 然 通 过 成 员 运 算 符. 进 行 同 结 构 体 类 似, 在 下 述 情 况 下 可 以 对 共 用 体 或 共 用 体 变 量 进 行 整 体 引 用 : 取 地 址 运 算 sizeof 运 算 以 及 同 类 型 共 用 体 变 量 之 间 的 赋 值 共 用 体 变 量 可 以 用 作 函 数 的 参 数, 也 可 用 作 函 数 的 返 回 值 例 5.4 共 用 体 变 量 的 使 用 #include"iostream.h" union data char c_data; short s_data; long l_data; ; void main() data x; x.c_data='m'; cout<< "c_data="<< x.c_data <<endl; x.s_data=10; cout<< "s_data="<< x.s_data <<endl; x.l_data=100l; cout<< "l_data="<< x.l_data <<endl; 运 行 程 序, 输 出 结 果 为 : c_data=m s_data=10 l_data=100 使 用 共 用 体 时 应 注 意 以 下 几 点 (1) 由 于 共 用 体 成 员 采 用 的 是 覆 盖 技 术, 因 此, 每 一 时 刻 共 用 体 变 量 只 有 一 个 成 员 起 作 用, 其 他 的 成 员 不 起 作 用, 即 最 后 一 次 存 放 的 成 员 起 作 用, 在 存 入 一 个 新 的 成 员 后 原 有 的 成 员 就 失 去 作 用 (2) 共 用 体 变 量 的 地 址 和 它 的 各 成 员 的 地 址 都 是 同 一 地 址
94 第 5 章 结 构 体 和 共 用 体 85 (3) 在 定 义 共 用 体 变 量 时 可 以 进 行 初 始 化, 但 只 能 对 共 用 体 变 量 的 第 一 个 成 员 进 行 初 始 化 这 是 由 于 共 用 体 变 量 在 任 意 时 刻 只 能 有 一 个 成 员 是 活 动 的, 编 译 器 在 为 共 用 体 变 量 分 配 内 存 时, 自 动 将 指 定 的 初 值 以 第 一 个 成 员 的 类 型 放 入 所 分 配 的 内 存 单 元 中 例 如 : data x='m'; 该 语 句 是 将 共 用 体 变 量 x 的 第 一 个 成 员 c_data 初 始 化 为 字 符 'm' (4) 共 用 体 可 以 作 为 结 构 体 的 成 员, 结 构 体 也 可 作 为 共 用 体 的 成 员, 也 可 以 定 义 共 用 体 数 组 习 题 1. 简 述 结 构 体 和 共 用 体 的 区 别 2. 定 义 一 个 结 构 体 教 师, 其 成 员 包 括 姓 名 性 别 年 龄 职 称 和 联 系 电 话 3. 分 析 下 面 程 序 的 运 行 结 果 #include"iostream.h" struct flower int num; // 花 号 char name[20]; // 花 名 char color[10]; // 花 色 float price; mudan=110245," 牡 丹 ","red",12; void main() cout<<mudan.num<<'\t'<<mudan.name<<'\t'<<mudan.color<<'\t'<<mudan.price<<endl;
95 第 6 章 指 针 和 引 用 C++ 语 言 在 程 序 运 行 时 具 有 获 得 变 量 的 地 址 并 对 地 址 进 行 操 作 的 能 力, 这 种 用 来 操 作 地 址 的 特 殊 类 型 变 量 就 是 指 针 指 针 是 保 存 内 存 地 址 的 变 量, 是 C++ 语 言 从 C 语 言 中 继 承 来 的 重 要 概 念, 是 C++ 语 言 区 别 于 其 他 程 序 设 计 语 言 的 最 重 要 的 特 征 之 一 C++ 语 言 中 的 指 针 所 具 有 的 保 存 内 存 地 址 的 功 能 使 得 程 序 员 可 以 直 接 管 理 计 算 机 内 存 正 确 而 灵 活 地 使 用 指 针, 可 以 有 效 地 表 示 更 加 复 杂 的 数 据 结 构, 可 以 使 设 计 出 来 的 程 序 简 洁 高 效 但 指 针 也 是 C++ 语 言 中 最 难 掌 握 的 概 念 之 一, 而 且 错 误 地 使 用 指 针 所 带 来 的 后 果 往 往 又 是 很 严 重 的, 有 时 甚 至 会 导 致 系 统 崩 溃 因 此, 正 确 使 用 指 针 是 C++ 语 言 学 习 的 重 点 和 难 点 之 一, 用 户 必 须 从 本 质 上 理 解 指 针, 并 大 胆 地 编 程 实 践 指 针 的 概 念 6.1 指 针 计 算 机 内 存 是 由 二 进 制 位 组 成 的, 为 了 便 于 访 问 和 管 理, 每 8 位 组 成 一 个 字 节, 一 个 字 节 称 为 一 个 存 储 单 元 通 常, 系 统 对 每 个 存 储 单 元 按 其 顺 序 进 行 编 号, 编 号 能 惟 一 地 确 定 任 何 一 个 字 节 的 位 置, 就 像 根 据 房 间 号 能 惟 一 确 定 任 何 一 个 房 间 一 样, 于 是 编 号 被 形 象 地 称 为 地 址 程 序 所 处 理 的 每 一 个 数 据 必 须 存 放 于 计 算 机 内 存 中 才 能 运 行, 这 些 数 据 都 要 占 用 一 定 的 存 储 空 间, 而 每 个 这 样 的 存 储 空 间 都 位 于 内 存 的 某 个 特 定 位 置, 都 有 一 个 惟 一 的 起 始 地 址 在 程 序 运 行 时, 系 统 将 利 用 内 存 存 储 相 关 的 数 据 数 据 在 内 存 中 的 存 储 方 式 为 : 按 其 所 属 的 数 据 类 型, 占 据 一 定 数 量 的 连 续 内 存 单 元 程 序 中 的 每 个 变 量 在 内 存 中 的 存 储 位 置 是 不 变 的, 具 有 固 定 的 存 储 地 址 因 为 地 址 指 示 了 字 节 在 存 储 器 中 的 位 置, 所 以 地 址 也 被 形 象 地 称 为 指 针 (pointer) 指 针 是 一 个 存 储 单 元 的 地 址 值, 用 来 存 放 地 址 ( 即 指 针 ) 的 变 量 也 称 指 针 变 量 在 上 下 文 意 义 明 确 的 情 况 下, 常 常 将 指 针 变 量 也 简 称 为 指 针 指 针 变 量 和 普 通 变 量 一 样 占 有 一 定 的 存 储 空 间, 但 它 与 普 通 变 量 的 区 别 在 于 指 针 变 量 的 存 储 空 间 中 存 放 的 不 是 普 通 的 数 据, 而 是 一 个 地 址 值 指 针 1. 指 针 的 声 明 指 针 是 一 个 变 量, 必 须 先 声 明 后 使 用 指 针 声 明 的 一 般 形 式 如 下 : 数 据 类 型 * 标 识 符 ; 其 中, 标 识 符 给 出 的 是 指 针 变 量 名, * 号 说 明 其 后 的 标 识 符 是 一 个 指 针 变 量, 数 据 类 型 可 以 是 C++ 语 言 中 任 一 合 法 的 类 型 例 如 : int *p1;
96 第 6 章 指 针 和 引 用 87 double *p2; 就 声 明 了 p1 p2 两 个 指 针 变 量 其 中 p1 指 向 int 型 变 量,p2 指 向 double 型 变 量 在 C++ 语 言 中 定 义 指 针 变 量 时, 以 下 形 式 均 是 合 法 的 : int* p //* 靠 左 double * q //* 两 边 都 不 靠 注 意 : 指 针 声 明 语 句 中 的 数 据 类 型 是 指 针 变 量 所 指 向 的 变 量 的 数 据 类 型, 即 指 针 变 量 所 指 向 的 存 储 单 元 中 存 储 数 据 的 数 据 类 型, 并 不 是 指 针 变 量 本 身 的 类 型, 任 一 指 针 变 量 本 身 数 据 值 的 类 型 都 是 unsigned long int 例 如, 上 例 中 声 明 的 指 针 变 量 p 称 为 int 型 指 针 变 量, 它 表 示 指 针 变 量 p 中 存 放 的 是 int 型 变 量 的 地 址,p 为 指 向 整 型 变 量 的 指 针 ; 而 q 为 double 型 指 针 变 量, 实 际 表 示 q 中 存 放 的 是 double 型 变 量 的 地 址 指 针 也 可 以 和 其 他 变 量 同 时 声 明 例 如 : int i,*p1; 该 语 句 就 声 明 了 一 个 整 型 变 量 i 和 一 个 整 型 指 针 变 量 p1 2. 指 针 变 量 运 算 符 (1) 取 地 址 运 算 符 & 该 运 算 符 表 示 对 & 后 面 的 变 量 进 行 取 地 址 运 算 例 如, 在 程 序 中 声 明 了 一 个 变 量 a, 则 &a 表 示 取 变 量 a 的 地 址, 该 表 达 式 的 值 为 变 量 a 的 首 地 址 既 然 指 针 变 量 是 用 来 存 放 变 量 地 址 的 变 量, 因 此 可 以 通 过 取 地 址 运 算 符 &, 将 某 一 变 量 的 地 址 赋 值 给 指 针 变 量 例 如 : int a=2,*p; p=&a; 定 义 了 整 型 变 量 a 和 指 向 a 的 指 针 变 量 p 若 变 量 a 的 地 址 为 0x00347FDF, 则 通 过 取 地 址 运 算 符 & 将 变 量 a 的 地 址 赋 值 给 指 针 变 量 p, 此 时 指 针 变 量 p 的 内 容 应 为 变 量 a 的 地 址 0x00347FDF, 如 图 6-1 所 示 指 针 变 量 p 变 量 a C++ 程 序 设 计 中, 当 声 明 一 个 变 量 时, 编 译 器 就 00347FDF FDF 会 自 动 地 根 据 指 定 的 数 据 类 型 为 该 变 量 分 配 相 应 的 内 存 因 此, 程 序 员 只 需 知 道 每 个 变 量 的 地 址 即 可 找 图 6-1 指 针 变 量 p 和 变 量 a 的 关 系 到 该 变 量, 必 要 时 可 以 使 用 取 地 址 运 算 符 & 来 获 取 变 量 的 地 址 例 6.1 变 量 地 址 及 取 地 址 运 算 符 的 使 用 #include"iostream.h" void main() int i=1; cout<<"i="<<i<<"\t 变 量 i 的 地 址 为 :"<<&i<<endl; 运 行 程 序, 输 出 显 示 结 果 : i=1 变 量 i 的 地 址 为 :0x0012FF7C 注 意 : 由 于 不 同 计 算 机 的 编 址 方 式 不 尽 相 同, 且 在 同 一 台 计 算 机 上 每 次 运 行 这 个 程 序 时, 编 译 器 为 该 变 量 i 分 配 的 地 址 也 不 一 定 相 同, 因 此, 上 面 列 出 的 地 址 输 出 结 果 与 读 者 在 实 际 运
97 88 C++ 程 序 设 计 行 时 的 结 果 可 能 并 不 相 同 (2) 间 接 访 问 运 算 符 * 该 运 算 符 也 称 指 针 运 算 符 或 取 内 容 运 算 符, 它 后 面 必 须 是 一 个 指 针 变 量, 表 示 访 问 该 指 针 变 量 所 指 向 的 变 量, 即 访 问 指 针 所 指 向 的 存 储 单 元 的 内 容 每 个 变 量 在 内 存 中 都 有 一 个 固 定 的 地 址, 而 指 针 中 保 存 的 就 是 变 量 的 地 址 值 如 果 声 明 了 一 个 指 针, 并 使 其 值 为 某 个 变 量 的 地 址, 则 可 以 通 过 这 个 指 针 间 接 地 访 问 在 这 个 地 址 中 存 储 的 变 量 利 用 指 针 来 访 问 变 量 需 要 使 用 间 接 访 问 运 算 符 * 例 如 : int i=1,*p=&i; cout<<*p; 其 中 第 2 条 语 句 将 输 出 变 量 i 的 值 1 当 然, 在 利 用 指 针 访 问 变 量 的 值 时, 也 可 以 给 变 量 赋 值, 例 如 : int i=1,*p=&i; *p=2; cout<<*p; 将 在 屏 幕 上 输 出 2 注 意 : 1 不 要 将 间 接 访 问 运 算 符 * 与 声 明 指 针 时 的 * 混 为 一 谈 指 针 声 明 时 的 * 是 指 针 变 量 声 明 的 标 识, 可 以 称 为 指 针 指 示 符, 而 间 接 访 问 运 算 符 * 用 来 访 问 指 针 所 指 向 的 变 量 2 通 过 以 上 的 说 明 可 以 看 出,* 运 算 和 & 运 算 互 为 逆 运 算 用 户 在 编 写 程 序 时 必 须 注 意 区 分 有 关 指 针 的 各 种 表 示 形 式 及 它 们 的 含 义 下 面 通 过 一 个 例 题 来 理 解 指 针 的 几 种 表 示 形 式 例 6.2 指 针 的 各 种 表 示 形 式 及 其 含 义 #include"iostream.h" void main() int a=10,*p; p=&a; *p=15; cout<<"a="<<a<<endl; cout<<"p="<<p<<endl; cout<<"&a="<<&a<<endl; cout<<"*p="<<*p<<endl; cout<<"&p="<<&p<<endl; 运 行 程 序, 输 出 显 示 结 果 : a=15 p=0x0012ff7c &a=0x0012ff7c
98 第 6 章 指 针 和 引 用 89 *p=15 &p=0x0012ff78 其 中,0x0012FF7C 是 指 针 变 量 p 的 值, 即 变 量 a 的 地 址 ; 而 0x0012FF78 是 指 针 变 量 p 的 地 址, 两 者 是 有 区 别 的, 如 图 6-2 所 示 指 针 变 量 p 变 量 a 3. 指 针 的 初 始 化 0012FF FF7C FF7C 如 果 用 户 声 明 了 一 个 指 针 变 量, 在 使 用 该 指 图 6-2 指 针 变 量 p 和 &p 的 关 系 针 变 量 之 前 必 须 对 它 赋 初 值 否 则, 在 程 序 中 使 用 该 指 针 变 量 就 有 可 能 导 致 系 统 崩 溃 与 其 他 变 量 一 样, 可 以 在 声 明 指 针 变 量 的 同 时, 通 过 初 始 化 来 给 指 针 变 量 赋 值 例 如 : int i,*p1=&i; int *p2=0; 其 中 第 1 条 语 句 将 指 针 变 量 p1 的 值 初 始 化 为 变 量 i 的 地 址, 第 2 条 语 句 将 指 针 变 量 p2 的 值 初 始 化 为 0 值 为 0 或 NULL 的 指 针 表 示 该 指 针 不 指 向 任 何 数 据, 又 称 空 指 针 为 使 用 安 全 起 见, 最 好 在 声 明 指 针 变 量 时 就 进 行 初 始 化, 即 使 是 初 始 化 为 空 指 针 也 可 以 如 果 在 声 明 指 针 变 量 时, 指 针 初 始 化 为 0 或 根 本 没 有 初 始 化, 在 使 用 前 就 必 须 给 它 赋 予 有 意 义 的 值 例 如 : int i,*p1; p1=&i 或 int *p1=0; int i; p1=&i; 都 是 正 确 的 由 于 数 组 名 表 示 的 是 该 数 组 的 首 地 址 值, 因 此, 如 果 声 明 指 针 变 量 指 向 一 个 数 组, 则 可 以 使 用 下 述 赋 值 方 法 : int x[5],*p1=x; 这 里 就 把 指 针 p1 初 始 化 为 指 向 数 组 x 的 指 针, 即 指 针 变 量 p1 指 向 数 组 x 的 第 一 个 元 素 x[0] 这 时, 不 需 要 使 用 取 地 址 运 算 符 & 当 然, 上 述 的 初 始 化 语 句 也 可 改 为 : int x[5],p1=&x[0]; 如 果 需 要 声 明 多 个 指 针 指 向 同 一 变 量, 可 以 采 取 下 述 方 法, 用 这 个 变 量 来 给 这 些 指 针 逐 个 赋 值 例 如 : int i,*p1=&i; int *p2=p1; 就 使 得 指 针 p1 和 p2 指 向 同 一 变 量 i 例 6.3 分 析 下 面 程 序 的 运 行 结 果 #include"iostream.h" void main()
99 90 C++ 程 序 设 计 int i=1,*p1=&i; int *p2=p1; cout<<"p1="<<p1<<",p2="<<p2<<endl; 程 序 的 输 出 结 果 为 : p1=0x0012ff7c,p2=0x0012ff7c 上 面 在 给 指 针 赋 值 时, 并 不 需 要 关 心 变 量 的 实 际 地 址 编 译 器 会 在 给 变 量 分 配 内 存 时, 自 动 保 证 所 分 内 存 地 址 的 合 法 性 但 是, 由 于 指 针 的 值 是 一 个 地 址, 当 然 也 可 以 直 接 用 一 个 实 际 的 地 址 值 来 给 它 赋 值 在 某 些 与 硬 件 直 接 打 交 道 的 程 序 中, 这 一 方 式 是 非 常 有 用 的 不 过, 在 用 常 量 地 址 值 给 指 针 赋 值 之 前, 必 须 明 确 该 地 址 所 代 表 的 内 存 单 元 的 作 用 对 于 初 学 者 来 说, 最 好 不 要 采 用 这 种 方 法, 否 则 错 误 地 使 用 内 存 单 元 有 可 能 对 整 个 计 算 机 系 统 造 成 严 重 的 后 果 下 面 来 看 一 些 对 指 针 的 错 误 赋 值 int i,*p1=i; // 不 能 给 指 针 赋 变 量 本 身 的 值, 应 将 变 量 的 地 址 值 赋 给 它 double *p2=&i; // 不 能 用 不 同 类 型 变 量 的 地 址 来 给 指 针 赋 值 如 果 确 实 需 要 用 不 同 类 型 变 量 的 地 址 给 指 针 赋 值, 就 应 该 采 用 强 制 类 型 转 换 例 如 : double *p2=(double *)&i; 注 意 : 必 须 避 免 下 面 的 错 误 int *p; *p=2; // 错 误, 指 针 P 没 有 初 始 化 这 里, 并 没 有 明 确 地 给 指 针 赋 一 个 地 址 值, 因 而 其 值 是 随 机 的 如 果 操 作 系 统 正 在 使 用 该 值 所 表 示 的 内 存 单 元, 这 时 向 其 中 写 入 一 个 值, 就 很 可 能 引 起 系 统 崩 溃 因 此, 在 使 用 指 针 前, 必 须 首 先 对 它 进 行 合 法 的 初 始 化 4. 指 针 的 运 算 指 针 是 一 个 变 量, 其 值 是 一 个 地 址 因 此, 它 只 能 参 与 赋 值 算 术 及 关 系 运 算 (1) 赋 值 运 算 一 个 没 有 被 赋 值 的 指 针 其 指 向 是 不 定 的, 或 是 一 个 空 指 针 使 用 指 向 未 定 的 指 针 进 行 指 针 操 作 时, 有 可 能 会 破 坏 内 存 中 某 些 区 域 的 内 容, 严 重 的 还 会 造 成 整 个 系 统 的 瘫 痪 因 此, 在 使 用 指 针 时 应 注 意 不 要 使 用 指 向 不 定 的 指 针 指 针 的 赋 值 运 算 可 以 通 过 指 针 的 初 始 化 实 现, 也 可 以 在 程 序 中 通 过 赋 值 语 句 来 实 现 (2) 算 术 运 算 指 针 可 以 和 整 数 进 行 加 减 运 算, 包 括 增 1 和 减 1 运 算, 其 实 质 是 地 址 的 运 算 设 p 和 q 是 指 向 具 有 相 同 数 据 类 型 的 一 组 数 据 的 指 针,n 是 整 数, 则 指 针 可 以 进 行 的 算 术 运 算 有 如 下 几 种 : p+n p n p++ p ++p p p q 这 里 需 要 指 出 的 是 指 针 的 算 术 运 算 与 一 般 的 数 值 计 算 不 同, 指 针 与 一 个 整 数 n 进 行 加 减 运 算 时, 它 不 是 简 单 地 将 指 针 的 地 址 值 加 上 或 减 去 给 定 的 整 数 n, 而 是 与 指 针 所 指 向 变 量 的 数 据 类 型 有 关 运 算 时 先 使 n 乘 上 一 个 比 例 因 子, 再 与 地 址 值 进 行 加 减 运 算 这 里 所 说 的 比 例 因 子 就 是 指 针 所 指 向 的 数 据 类 型 在 存 储 空 间 中 实 际 所 占 的 字 节 数 如 对 char,int,float,long 和 double 型 数 据, 比 例 因 子 分 别 为 1,4,4,4 和 8
100 第 6 章 指 针 和 引 用 91 因 此,p±n 表 示 的 实 际 位 置 的 地 址 值 是 p±n* 比 例 因 子 由 此 可 见, 指 针 进 行 算 术 运 算 后 的 结 果 仍 为 地 址 量, 只 是 指 针 前 移 或 后 移 了 若 干 个 存 储 单 元 如 果 两 个 指 针 所 指 向 的 变 量 类 型 相 同, 也 可 以 对 它 们 直 接 进 行 减 法 运 算 例 如 : p1 p2; 运 算 结 果 是 一 个 整 数 值, 它 的 绝 对 值 就 是 两 个 指 针 所 指 向 的 地 址 之 间 相 隔 数 据 的 个 数 (3) 关 系 运 算 两 个 指 针 进 行 关 系 运 算 时, 它 们 必 须 指 向 同 一 连 续 存 储 空 间 指 针 的 关 系 运 算 一 般 在 指 向 相 同 类 型 变 量 的 指 针 之 间 进 行, 表 示 它 们 所 指 向 的 变 量 在 内 存 中 的 位 置 关 系 例 如 : int a; int *p1=&a;*p2=p1; 所 声 明 的 两 个 指 针 做 p1==p2 运 算, 其 结 果 为 1(true), 即 指 针 p1 和 p2 指 向 同 一 个 变 量 对 于 其 他 关 系 运 算, 和 上 面 类 似, 比 较 的 也 是 两 个 指 针 所 指 向 的 地 址 值 的 大 小 不 过, 一 般 用 在 对 数 组 进 行 操 作 的 场 合 指 针 与 整 数 0 之 间 可 以 进 行 等 与 不 等 的 关 系 运 算, 即 p==0 或 p!=0 用 于 测 试 指 针 是 否 为 空 指 针 5. 多 级 指 针 指 针 是 一 个 变 量, 在 内 存 中 占 据 一 定 的 存 储 空 间, 具 有 一 个 地 址, 这 个 地 址 也 可 以 利 用 指 针 来 保 存 因 此, 可 以 声 明 一 个 指 针 来 指 向 它, 这 个 指 针 称 为 指 向 指 针 的 指 针, 即 二 级 指 针 二 级 指 针 是 指 针 变 量 的 指 针, 使 用 二 级 指 针 可 以 实 现 更 为 复 杂 的 功 能 声 明 二 级 指 针 的 格 式 为 : 数 据 类 型 ** 标 识 符 其 中, 两 个 * 号 表 示 二 级 指 针, 标 识 符 为 二 级 指 针 的 名 字, 数 据 类 型 是 指 通 过 两 次 间 接 寻 址 后 所 访 问 的 变 量 的 类 型 例 如 : int i,*p1=&i; int **p2=&p; p2 就 是 二 级 指 针, 它 指 向 指 针 变 量 p1 注 意 : 虽 然 p1 和 p2 都 是 指 针 变 量, 其 值 都 是 地 址, 所 定 义 的 数 据 类 型 也 都 是 int 型, 但 下 面 的 赋 值 语 句 是 错 误 的 : p2=&i; 原 因 在 于 p2 是 二 级 指 针, 它 应 该 指 向 一 个 指 针 变 量, 而 不 是 指 向 一 个 普 通 变 量 依 此 类 推, 可 以 用 多 个 * 号 声 明 多 级 指 针, 不 过 超 过 二 级 的 多 级 指 针 在 实 际 编 程 中 可 能 很 少 遇 到 例 6.4 二 级 指 针 的 使 用 #include"iostream.h" void main() int i; int *p1=&i,**p2=&p1; // 声 明 二 级 指 针 p2
101 92 C++ 程 序 设 计 i=1; cout<<"i="<<i<<endl; cout<<"*p1="<<*p1<<endl; cout<<"p1="<<p1<<endl; cout<<"*p2="<<*p2<<endl; cout<<"p2="<<p2<<endl; cout<<"**p2="<<**p2<<endl; 运 行 程 序, 输 出 结 果 为 : i=1 *p1=1 p1=0x0012ff7c *p2=0x0012ff7c p2=0x0012ff78 **p2=1 注 意 : 读 者 在 运 行 程 序 时, 输 出 地 址 可 能 随 计 算 机 的 不 同 而 略 有 差 异 指 针 与 数 组 在 C++ 语 言 中, 数 组 名 表 示 的 是 该 数 组 的 首 地 址 值, 也 就 是 说 数 组 名 就 是 指 向 数 组 第 一 个 元 素 的 指 针 常 量 因 此, 指 针 与 数 组 之 间 存 在 着 密 切 的 关 系 数 组 在 内 存 中 的 起 始 地 址 称 为 数 组 的 指 针, 数 组 元 素 在 内 存 中 的 起 始 地 址 称 为 数 组 元 素 的 指 针 用 来 保 存 数 组 指 针 的 变 量 称 为 数 组 的 指 针 变 量, 简 称 为 数 组 的 指 针 用 来 保 存 数 组 元 素 指 针 的 变 量 称 为 数 组 元 素 的 指 针 变 量, 简 称 为 数 组 元 素 的 指 针 1. 用 指 针 访 问 数 组 元 素 对 于 一 维 数 组 来 说, 指 向 数 组 的 指 针 变 量 与 指 向 数 组 元 素 的 指 针 变 量 的 定 义 方 法 都 与 普 通 变 量 的 指 针 的 定 义 方 法 一 样, 都 是 一 级 指 针 例 如, 对 于 下 面 声 明 的 数 组 : int x[5],*p1; // 定 义 数 组 x 及 指 针 变 量 p1 p1=x; // 将 数 组 的 起 始 地 址 赋 给 指 针 变 量 p1, 使 p1 指 向 数 组 x 数 组 名 x 代 表 数 组 的 起 始 地 址, 实 际 上 就 是 指 向 第 一 个 元 素 x[0] 的 指 针 ;*x 表 示 的 就 是 元 素 x[0] 的 值, 而 *(x+2) 则 表 示 访 问 元 素 x[2] 的 值 指 针 加 减 运 算 一 般 用 在 对 数 组 元 素 进 行 操 作 的 场 合 由 于 数 组 在 内 存 中 是 顺 序 存 储 的, 因 此, 一 旦 声 明 了 某 个 指 针 指 向 数 组 中 的 一 个 元 素, 就 可 以 通 过 指 针 和 整 数 的 加 减 运 算 ( 包 括 增 1 和 减 1 运 算 ) 来 访 问 这 个 数 组 的 每 个 元 素 由 于 数 组 名 本 身 就 是 指 向 数 组 第 一 个 元 素 的 指 针 常 量, 因 此, 可 以 通 过 它 来 访 问 其 中 的 元 素 例 6.5 通 过 数 组 名 访 问 数 组 元 素 #include"iostream.h" void main() int x[5]=1,2,3,4,5;
102 第 6 章 指 针 和 引 用 93 for(int i=0;i<5;i++) cout<<x[i]<<'\t'; cout<<endl; for(i=0;i<5;i++) cout<<*(x+i)<<'\t'; cout<<endl; 运 行 程 序, 将 输 出 结 果 : 从 例 6.5 可 知, 利 用 数 组 名 来 访 问 数 组 元 素 与 利 用 数 组 下 标 的 效 果 是 一 样 的 此 外, 也 可 以 在 程 序 中 声 明 一 个 与 数 组 元 素 类 型 相 同 的 指 针, 然 后 使 之 指 向 数 组 的 某 个 元 素 通 过 这 个 指 针 同 样 也 能 访 问 到 数 组 中 的 每 个 元 素, 例 如 : int x[5]; int *p=x; 其 中 声 明 的 指 针 指 向 数 组 int x[5] 的 第 一 个 元 素 因 此, 通 过 它 就 可 以 访 问 到 这 个 数 组 中 的 每 一 个 元 素 例 如,*(p+2) 同 样 表 示 元 素 x[2] 的 值 例 6.6 利 用 指 向 数 组 某 个 元 素 的 指 针 访 问 数 组 中 的 每 个 元 素 #include"iostream.h" void main() int x[5]; int *p=x; // 声 明 指 针 指 向 数 组 的 第 一 个 元 素 for(int i=0;i<5;i++) // 利 用 数 组 下 标 的 方 法 给 数 组 元 素 赋 值 x[i]=i; for(i=0;i<5;i++) // 利 用 指 向 数 组 的 指 针 输 出 数 组 的 元 素 值 cout<<*p++<<'\t'; cout<<endl; p=x; for(i=0;i<5;i++) // 利 用 指 向 数 组 的 指 针 给 数 组 元 素 赋 值
103 94 C++ 程 序 设 计 *p++=2*i; p=x; for(i=0;i<5;i++) cout<<*p++<<'\t'; cout<<endl; 运 行 程 序, 将 输 出 结 果 : 通 过 以 上 两 个 例 题 的 比 较, 可 以 看 出 数 组 元 素 的 访 问, 既 可 用 下 标 法, 也 可 用 指 针 法 下 标 法 简 单 直 观, 指 针 法 在 采 用 指 针 变 量 的 自 增 或 自 减 运 算 时, 能 使 目 标 程 序 变 短, 运 行 速 度 变 快 如 果 要 访 问 数 组 的 第 i 个 元 素, 则 下 标 法 和 指 针 法 分 别 如 下 (1) 下 标 法 1 数 组 名 下 标 法 :x[i] 2 指 针 变 量 下 标 法 :p[i] (2) 指 针 法 1 数 组 名 指 针 法 :x+i 表 示 数 组 元 素 x[i] 的 地 址,*(x+i) 表 示 数 组 元 素 x[i] 2 指 针 变 量 指 针 法 :p+i 表 示 数 组 元 素 x[i] 的 地 址,*(p+i) 表 示 数 组 元 素 x[i] 在 使 用 指 向 一 维 数 组 的 指 针 变 量 时, 要 注 意 以 下 几 点 (1)p+i 并 不 是 简 单 地 使 指 针 变 量 的 值 加 上 i, 而 是 p+i*n, 其 中 n 是 数 组 元 素 所 占 用 的 字 节 数 例 如, 字 符 型 数 组 元 素 占 用 1 字 节, 整 型 数 组 元 素 占 用 4 字 节 等 假 设 int 型 指 针 变 量 p 的 当 前 值 为 1000, 则 p+3 所 指 的 存 储 单 元 实 际 上 为 *4=100C, 而 不 是 1003 (2) 利 用 指 针 对 数 组 进 行 操 作 时, 还 必 须 注 意 越 界 问 题 例 如 : int x[5]; int *p=x; // 指 针 p 指 向 数 组 x 的 首 地 址 p=p+5; *p=10; 就 是 错 误 的 这 是 因 为 数 组 x 共 有 5 个 元 素, 数 组 下 标 0~4, 而 p=p+5 已 经 使 指 针 p 指 向 的 地 址 位 于 第 6 个 元 素, 即 已 经 在 数 组 之 外, 表 达 式 *p=10 在 这 个 地 址 中 写 入 值 有 可 能 造 成 严 重 的 后 果 (3) 可 以 通 过 改 变 指 针 变 量 本 身 值 的 方 法 ( 如 p++) 来 指 向 不 同 的 数 组 元 素, 但 是 数 组 名 表 示 数 组 的 起 始 地 址, 是 一 个 地 址 常 量, 是 不 能 改 变 的, 如 写 成 x++ 就 是 错 误 的 (4) 要 注 意 指 针 变 量 的 当 前 值 例 6.7 分 析 下 面 的 程 序 #include"iostream.h" void main()
104 第 6 章 指 针 和 引 用 95 int x[5], *p=x ; for(int i=0;i<5;i++) cin>>*p++; for(i=0;i<5;i++) cout<<*p++<<'\t'; cout<<endl; 运 行 程 序 后, 用 户 输 入 1,2,3,4,5 后 回 车, 屏 幕 上 输 出 显 示 如 下 : 显 然, 输 出 结 果 是 错 误 的, 并 不 是 用 户 希 望 的 1,2,3,4,5 原 因 在 于 经 过 第 一 个 for 循 环 后, 指 针 p 已 指 向 数 组 x 的 末 尾, 因 此 在 执 行 第 二 个 for 循 环 时,p 的 值 已 不 是 &x[0], 而 是 x+5, 从 而 导 致 输 出 结 果 出 现 错 误 纠 正 错 误 的 方 法 是 在 第 二 个 for 循 环 之 前 重 置 指 针 变 量 p, 使 其 指 向 数 组 x 的 起 始 地 址 即 可, 即 在 第 二 个 for 循 环 之 前 加 一 条 语 句 :p=x 2. 指 针 数 组 由 指 针 组 成 的 数 组 称 为 指 针 数 组, 即 指 针 数 组 的 每 一 个 元 素 都 是 指 针 指 针 数 组 常 用 于 指 向 多 个 字 符 串, 使 字 符 串 处 理 更 加 方 便 灵 活 声 明 指 针 数 组 的 一 般 格 式 如 下 : 数 据 类 型 * 数 组 名 [ 常 量 表 达 式 1][ 常 量 表 达 式 2] ; 其 中, 数 据 类 型 是 指 数 组 中 各 元 素 指 针 所 指 向 的 类 型, 同 一 指 针 数 组 中 各 指 针 元 素 指 向 的 类 型 相 同 ; 数 组 名 是 一 个 标 识 符, 是 这 个 数 组 的 名 字, 即 数 组 的 首 地 址 数 组 中 每 个 元 素 都 是 一 个 指 针 例 如 : int *p1[6]; double *p2[3][4]; 就 分 别 声 明 了 含 有 6 个 元 素 的 一 维 int 型 指 针 数 组 p1 和 含 有 12 个 元 素 的 二 维 double 型 指 针 数 组 p2 例 6.8 指 针 数 组 的 使 用 #include"iostream.h" void main() int x[2][3]=1,2,3,4,5,6; int i,j; int *p[2]=x[0],x[1]; // 声 明 指 针 数 组 并 初 始 化 for(i=0;i<2;i++)
105 96 C++ 程 序 设 计 for(j=0;j<3;j++) cout<<*(p[i]+j)<<'\t'; // 利 用 指 针 数 组 输 出 其 指 向 的 元 素 的 值 cout<<endl; 运 行 程 序, 将 输 出 结 果 : 指 针 数 组 在 使 用 前 也 必 须 首 先 赋 值, 当 然 也 可 以 利 用 初 始 化 赋 值 在 例 6.8 中, 首 先 声 明 了 一 个 二 维 数 组 x[2][3] 并 赋 初 值 在 第 6 行 声 明 了 一 个 指 针 数 组 *p[2] 并 对 它 进 行 了 初 始 化, 在 这 里 用 于 初 始 化 的 是 x[0] 和 x[1], 它 们 分 别 表 示 数 组 元 素 x[0][0] 及 x[1][0] 的 地 址 读 者 可 以 把 语 句 : cout<<*(p[i]+j)<<'\t'; 修 改 为 : cout<<p[i][j]<< '\t'; 运 行 程 序, 结 果 与 原 程 序 是 一 样 的 3. 数 组 指 针 数 组 指 针 就 是 一 个 指 向 数 组 的 指 针, 其 声 明 格 式 如 下 : 数 据 类 型 (* 指 针 名 )[ 常 量 表 达 式 1][ 常 量 表 达 式 2] ; 其 中,(* 指 针 名 ) 中 的 圆 括 号 不 能 省 略, 原 因 在 于 方 括 号 的 优 先 级 别 比 * 高 例 如 : int (*p)[5]; 声 明 了 一 个 指 向 具 有 5 个 元 素 的 int 型 数 组 的 指 针 如 果 省 略 圆 括 号, 则 编 译 器 将 把 上 面 的 语 句 解 释 为 : int *(p[5]); 这 显 然 不 符 合 程 序 设 计 的 初 衷 例 6.9 利 用 数 组 指 针 改 写 例 6.8 #include"iostream.h" void main() int x[2][3]=1,2,3,4,5,6; int i,j; int (*p)[3]=x; for(i=0;i<2;i++) for(j=0;j<3;j++)
106 第 6 章 指 针 和 引 用 97 cout<<p[i][j]<<'\t'; cout<<endl; 带 下 划 线 的 语 句 是 和 原 程 序 有 区 别 的 语 句 运 行 程 序 后 输 出 结 果 与 例 6.8 完 全 一 样 指 针 与 字 符 串 在 C++ 语 言 中, 字 符 串 被 表 示 成 一 个 字 符 数 组 因 此, 有 时 也 把 字 符 串 称 为 字 符 数 组 由 于 字 符 串 中 的 每 一 个 字 符 对 应 字 符 数 组 中 的 一 个 数 组 元 素, 因 此 用 户 可 以 利 用 指 针 指 向 字 符 数 组 中 的 任 何 一 个 数 组 元 素, 即 指 向 字 符 串 中 的 任 何 一 个 字 符 例 如 : char *s1="hello World!"; 表 面 上 看, 该 语 句 虽 然 没 有 定 义 字 符 数 组, 但 系 统 实 际 上 在 内 存 中 开 辟 了 一 个 字 符 数 组 来 存 放 字 符 串 常 量, 并 将 字 符 串 的 首 地 址 ( 即 存 放 字 符 串 的 字 符 数 组 的 首 地 址 ) 赋 给 字 符 指 针 变 量 s1 该 语 句 等 价 于 下 面 两 条 语 句 : char *s1; s1="hello World!"; s1 是 一 个 指 向 字 符 型 数 组 的 指 针 变 量, 在 这 里 把 字 符 串 Hello World! 的 首 地 址 赋 给 指 针 变 量 s1, 而 不 是 把 字 符 串 Hello World! 的 每 一 个 字 符 存 放 到 s1 中 在 C++ 语 言 中, 字 符 串 既 可 以 用 字 符 数 组 表 示, 也 可 以 用 字 符 指 针 变 量 来 表 示 例 如, 定 义 一 个 20 个 字 符 的 字 符 数 组 a 的 语 句 为 :char a[20] 用 户 可 以 在 定 义 字 符 数 组 的 同 时 进 行 初 始 化 例 如 :char a[ ]= "How are you!" 该 字 符 串 包 括 空 格 共 有 12 个 字 符, 但 是 在 内 存 中 存 储 的 字 符 串 的 长 度 是 13 而 不 是 12, 原 因 在 于 系 统 在 内 存 中 保 存 该 字 符 串 时, 在 该 字 符 串 的 最 后 加 上 了 一 个 '\0' 字 符 来 表 示 字 符 串 结 束, 所 以 字 符 串 的 长 度 变 为 13 C++ 规 定 : 字 符 数 组 的 最 后 一 个 元 素 必 须 是 '\0' 字 符 所 以 一 个 25 个 元 素 的 字 符 数 组 只 能 存 放 24 个 字 符 在 引 用 字 符 串 时, 既 可 以 逐 个 字 符 引 用, 也 可 以 作 为 一 个 整 体 引 用 例 6.10 分 析 下 面 程 序 的 运 行 结 果 #include "string.h" #include "iostream.h" void main() char a[]="01234",b[]="56789"; char *sa=a,*sb=b; for(int i=0;i<5;i++) *sa++=*sb++; cout<<a<<endl; cout<<b<<endl;
107 98 C++ 程 序 设 计 运 行 程 序, 输 出 结 果 为 : 指 针 与 函 数 1. 指 针 作 为 函 数 的 参 数 函 数 的 参 数 可 以 是 C++ 语 言 中 任 意 的 合 法 变 量, 当 然 也 可 以 是 指 针 如 果 函 数 的 参 数 是 指 针, 对 这 个 函 数 的 调 用 就 是 传 址 调 用 在 进 行 传 址 调 用 时, 函 数 的 实 参 传 递 给 形 参 的 是 一 个 地 址, 从 而 使 得 形 参 指 针 和 实 参 指 针 指 向 同 一 个 地 址 因 此, 被 调 用 函 数 中 对 形 参 指 针 所 指 向 的 地 址 中 内 容 的 任 何 改 变 都 会 影 响 到 实 参 例 6.11 利 用 指 针 作 为 函 数 参 数 交 换 实 参 变 量 的 值 #include"iostream.h" void swap(int *a,int *b); void main() int x=1,y=2; cout<<" 交 换 前 "<<endl; cout<<"x="<<x<<",y="<<y<<endl; swap(&x,&y); cout<<" 交 换 后 "<<endl; cout<<"x="<<x<<",y="<<y<<endl; void swap(int *a,int *b) int temp; temp=*a; *a=*b; *b=temp; 运 行 程 序, 输 出 结 果 : 交 换 前 x=1,y=2 交 换 后 x=2,y=1 由 上 例 可 以 看 出, 在 程 序 中 采 取 传 址 调 用 时, 数 据 无 论 在 主 调 函 数 main 中, 还 是 在 被 调 函 数 swap 中, 都 使 用 同 一 个 存 储 空 间, 故 被 调 函 数 中 对 形 参 指 向 的 值 的 改 变 必 然 影 响 到 实 参, 所 以 能 够 实 现 实 参 变 量 的 值 的 互 换 不 过 有 3 点 需 要 强 调 : 一 是 swap 函 数 必 须 以 指 针 变 量 *x 和 *y 作 为 形 参, 以 便 接 收 传 入 的
108 第 6 章 指 针 和 引 用 99 地 址 ; 二 是 main 函 数 中 应 以 变 量 的 地 址 &a 和 &b 作 为 实 参 来 调 用 swap 函 数, 即 传 址 调 用, 以 便 将 实 参 的 地 址 传 给 相 应 的 形 参 ; 三 是 swap 函 数 中 用 指 针 变 量 x 和 y 间 接 访 问 相 应 的 实 参, 以 改 变 实 参 变 量 的 值 这 三 者 配 合 才 能 完 成 交 换 实 参 变 量 x 和 y 值 的 目 的 如 果 将 swap 函 数 修 改 如 下, 请 读 者 试 一 下 会 出 现 什 么 输 出 结 果 void swap(int a,int b) int temp; temp=a; a=b; b=temp; 注 意 : 在 函 数 的 传 址 调 用 中, 传 递 的 参 数 的 值 并 不 改 变, 也 即 指 针 本 身 的 值 并 不 改 变, 改 变 的 是 它 指 向 的 值 2. 数 组 作 为 函 数 的 参 数 数 组 名 代 表 数 组 所 在 存 储 空 间 的 首 地 址, 它 本 身 就 是 一 个 指 针, 故 数 组 名 也 可 以 作 为 函 数 的 参 数, 这 也 属 于 传 址 调 用 此 时 并 不 是 将 整 个 数 组 传 递 给 被 调 用 函 数, 传 递 的 只 是 数 组 的 首 地 址 例 6.12 将 一 个 数 组 中 的 元 素 前 后 逆 置 #include"iostream.h" void transpose(int x[],int n); void main() int a[6]=1,2,3,4,5,6; int i; cout<<" 原 数 组 :"; for(i=0;i<6;i++) cout<<'\t'<<a[i]; cout<<endl; transpose(a,6); cout<<" 逆 置 后 :"; for(i=0;i<6;i++) cout<<'\t'<<a[i]; cout<<endl; void transpose(int x[],int n) int temp,i; for(i=0;i<n;i++,n- -)
109 100 C++ 程 序 设 计 temp=x[i]; x[i]=x[n 1]; x[n 1]=temp; 运 行 程 序, 将 输 出 结 果 : 原 数 组 : 逆 置 后 : 例 6.13 用 选 择 排 序 法 把 n 个 整 数 按 从 大 到 小 的 顺 序 排 列 选 择 排 序 法 的 思 想 : 第 1 轮 从 n 个 元 素 中 选 择 最 大 的 一 个 元 素, 把 它 和 位 于 第 1 个 位 置 的 元 素 互 换 ; 第 2 轮 在 剩 下 的 n 1 个 元 素 中 选 择 次 大 的 一 个 元 素, 把 它 和 位 于 第 2 个 位 置 的 元 素 互 换 ; 第 n 1 轮 在 剩 下 的 两 个 元 素 中 选 择 较 大 的 一 个 元 素, 把 它 和 位 于 第 n 1 个 位 置 的 元 素 互 换, 最 后 剩 下 的 一 个 元 素 必 然 是 最 小 的, 排 序 完 成 #include"iostream.h" #define n 8 void sort(int x[],int m); void main() int a[n],i; cout<<" 请 输 入 要 排 序 的 8 个 整 数 "<<endl; for(i=0;i<n;i++) cin>>a[i]; // 从 键 盘 输 入 要 排 序 的 数 据 sort(a,n); // 用 选 择 排 序 法 实 现 降 序 排 列 cout<<" 排 序 结 果 为 "<<endl; for(i=0;i<n;i++) cout<<a[i]<< ''; // 输 出 排 序 结 果 cout<<endl; void sort(int x[],int m) int i,j,k,t; for(i=0;i<m-1;i++) // 外 循 环, 控 制 循 环 次 数 k=i; // 预 置 本 轮 次 最 大 元 素 的 下 标 值 for(j=i+1;j<m;j++) // 内 循 环, 筛 选 出 本 轮 次 最 大 的 元 素 if(x[j]>x[k]) k=j; // 存 在 更 大 元 素, 保 存 其 下 标 if(k!=i) t=x[i]; // 交 换 位 置
110 第 6 章 指 针 和 引 用 101 x[i]=x[k]; x[k]=t; 运 行 程 序, 输 出 结 果 为 : 请 输 入 要 排 序 的 8 个 整 数 : 排 序 结 果 为 : 动 态 内 存 分 配 通 过 指 针 可 以 间 接 访 问 它 所 指 向 的 变 量 读 者 可 能 会 产 生 疑 问 : 既 然 可 以 用 变 量 名 直 接 访 问 其 值, 这 样 做 又 有 什 么 意 义 呢? 确 实 如 此, 在 实 际 的 程 序 设 计 中, 很 少 这 样 使 用 指 针, 之 所 以 这 样 仅 仅 是 为 了 讲 解 指 针 的 工 作 原 理 但 是 在 有 些 情 况 下, 比 如 进 行 动 态 内 存 分 配 时, 就 必 须 用 指 针 来 访 问 内 存 C++ 语 言 要 求 程 序 中 的 变 量 在 使 用 前 必 须 首 先 声 明, 以 便 编 译 器 预 先 为 每 个 变 量 分 配 相 应 的 内 存 空 间 但 是, 我 们 考 虑 一 种 情 况 : 如 果 要 设 计 一 个 通 用 的 学 生 信 息 管 理 系 统, 学 生 类 数 组 元 素 个 数 声 明 为 多 少 才 算 合 适 呢? 因 为 有 的 学 校 可 能 有 几 千 个 学 生, 而 有 的 学 校 则 有 几 万, 甚 至 十 几 万 学 生 很 显 然, 为 了 满 足 需 要, 学 生 类 数 组 声 明 得 越 大 越 好 但 这 又 会 带 来 另 一 个 问 题 : 如 果 一 个 学 校 的 学 生 很 少, 岂 不 是 白 白 地 浪 费 了 大 量 的 内 存 空 间? 为 此,C++ 语 言 提 供 了 一 种 被 称 作 动 态 内 存 分 配 的 方 法 动 态 内 存 分 配 是 指 在 程 序 运 行 期 间 根 据 实 际 需 要 随 时 申 请 内 存, 并 在 不 需 要 时 释 放, 它 实 际 是 一 种 在 程 序 运 行 时 动 态 申 请 和 释 放 内 存 的 技 术 应 用 程 序 数 据 所 占 的 内 存 可 以 分 为 3 类 : 静 态 存 储 区 栈 和 堆 在 程 序 运 行 开 始 前 就 分 配 的 存 储 空 间 都 在 静 态 存 储 区 中, 而 局 部 变 量 在 栈 中 分 配 存 储 空 间, 堆 也 称 为 自 由 存 储 单 元 动 态 内 存 分 配 就 是 在 堆 中 进 行 的 在 进 行 动 态 内 存 分 配 时 需 要 使 用 运 算 符 new 和 运 算 符 delete, 相 应 地 我 们 把 申 请 和 释 放 内 存 的 过 程 称 作 创 建 和 删 除 1. 运 算 符 new 运 算 符 new 用 于 申 请 所 需 的 内 存 单 元, 它 的 使 用 格 式 如 下 : < 数 据 类 型 > *< 指 针 变 量 > = new < 数 据 类 型 >; 其 中, 指 针 指 向 的 数 据 类 型 应 与 关 键 字 new 后 给 定 的 类 型 相 同 关 键 字 new 的 作 用 是 从 堆 中 为 程 序 分 配 指 定 数 据 类 型 所 需 的 内 存 单 元 若 分 配 成 功, 则 返 回 其 首 地 址 ; 否 则, 返 回 一 个 空 指 针 new 返 回 的 内 存 地 址 必 须 赋 给 指 针 例 如 : int *pi; // 整 型 指 针 float *pf; // 浮 点 类 型 指 针 pi= new int; // 为 一 个 整 数 类 型 的 数 分 配 内 存 pf = new float; // 为 一 个 浮 点 类 型 的 数 分 配 内 存 说 明 : 如 果 分 配 成 功, 则 返 回 一 个 指 向 该 分 配 空 间 的 指 针 ; 如 果 此 空 间 不 可 用 或 者 分 配 空 间 失 败 或 者 检 测 到 某 些 错 误, 则 返 回 零 或 空 指 针 因 此, 在 实 际 编 程 时, 对 于 动 态 内 存 分 配,
111 102 C++ 程 序 设 计 应 在 分 配 操 作 结 束 后, 首 先 检 查 返 回 的 地 址 值 是 否 为 零, 以 确 认 内 存 申 请 是 否 成 功 在 内 存 分 配 成 功 后, 就 可 以 使 用 这 个 指 针 了 例 如 : *pi=10; 就 是 把 值 10 赋 给 指 针 pi 所 指 向 的 int 型 内 存 单 元 与 其 他 变 量 类 似, 在 动 态 申 请 内 存 时, 也 可 以 同 时 对 分 配 的 内 存 单 元 进 行 初 始 化 例 如 : int *p=new int(10); 就 为 所 申 请 的 内 存 单 元 指 定 了 初 值 10, 若 内 存 分 配 成 功, 其 中 的 内 容 就 为 整 数 10 这 里, 圆 括 号 中 的 内 容 实 际 上 可 以 是 任 意 与 内 存 单 元 类 型 相 同 的 表 达 式 在 堆 中 也 可 以 用 运 算 符 new 申 请 一 块 保 存 数 组 的 内 存 单 元, 即 创 建 一 个 数 组 创 建 一 个 数 组 的 格 式 如 下 : 指 针 = new 数 据 类 型 [ 下 标 表 达 式 ] 其 中, 指 针 的 类 型 应 与 关 键 字 new 后 给 出 的 数 据 类 型 相 同, 下 标 表 达 式 给 出 的 是 数 组 元 素 的 个 数 如 果 内 存 分 配 成 功, 运 算 符 new 将 返 回 一 个 指 向 分 配 的 内 存 首 地 址 的 指 针, 该 指 针 的 类 型 与 上 述 表 达 式 中 给 定 的 相 同 ; 当 然, 如 果 分 配 内 存 失 败, 返 回 的 将 是 空 指 针 与 其 他 情 形 不 同 的 是, 在 为 数 组 动 态 分 配 内 存 时, 不 能 对 数 组 中 的 元 素 初 始 化 因 此, 对 于 创 建 数 组 的 情 形, 相 应 的 类 声 明 中 必 须 有 默 认 构 造 函 数 例 如 : int *p=new int[5]; Date *pdate=new Date[5]; 就 分 别 在 堆 中 创 建 了 一 个 整 数 数 组 和 Date 类 的 对 象 数 组 但 是 下 面 的 语 句 就 是 错 误 的 : int *p=new int[5]=1,2,3,4,5; // 错 误, 不 可 初 始 化 需 要 注 意 的 事, 由 运 算 符 new 动 态 分 配 的 存 储 空 间 的 生 存 周 期 是 任 意 的, 只 有 在 程 序 中 使 用 运 算 符 delete 释 放 它 们 时, 其 生 存 周 期 才 结 束 2. 运 算 符 delete 当 程 序 中 不 再 需 要 使 用 运 算 符 new 申 请 到 的 某 个 内 存 单 元 时, 就 必 须 用 运 算 符 delete 来 释 放 它 这 一 操 作 的 表 述 形 式 如 下 : delete 指 针 名 ; // 释 放 非 数 组 内 存 单 元 delete[] 指 针 名 ; // 释 放 数 组 内 存 单 元 其 中, 指 针 名 是 指 向 需 要 释 放 的 内 存 单 元 的 指 针 的 名 字 与 在 堆 中 使 用 运 算 符 new 创 建 对 象 时 需 调 用 构 造 函 数 类 似, 使 用 运 算 符 delete 时 也 需 要 调 用 相 应 类 的 析 构 函 数 另 外, 还 应 注 意 在 这 一 操 作 中, 指 针 本 身 并 不 被 删 除, 必 要 时 可 以 重 新 赋 值 在 释 放 数 组 内 存 单 元 时, 运 算 符 后 必 须 加 上 [] 号 如 果 未 加 [] 号, 就 只 是 释 放 数 组 的 第 一 个 元 素 占 据 的 内 存 单 元 例 如 : int *p1=new int(1); Date *p2=new Date[5]; delete pl; delete []p2; 在 进 行 动 态 内 存 分 配 时, 必 须 注 意 指 向 分 配 内 存 的 指 针 可 以 是 一 个 局 部 变 量, 但 它 所 指 向 的 内 存 除 非 程 序 显 示 释 放 它, 否 则 直 到 程 序 运 行 结 束, 它 一 直 都 被 占 据 着 因 此, 当 程 序 从 声 明 指 针 的 函 数 返 回 前, 必 须 利 用 该 指 针 删 除 在 函 数 中 申 请 的 内 存 单 元 否 则, 指 针 将 退 出 作 用 域, 不 能 再 用, 那 么 这 个 内 存 单 元 在 整 个 程 序 运 行 结 束 前 都 无 法 释 放, 从 而 不 能 再 用, 这 就 是
112 第 6 章 指 针 和 引 用 103 内 存 遗 漏 问 题 如 果 需 要 继 续 使 用 这 个 内 存 单 元, 就 需 要 将 指 针 的 值 返 回 给 主 调 函 数 这 时, 当 然 就 不 应 删 除, 不 过 这 时 应 该 考 虑 在 主 调 函 数 中 申 请 内 存, 并 把 它 传 给 被 调 函 数 同 样, 对 于 指 向 动 态 分 配 的 内 存 的 指 针, 在 其 指 向 的 内 存 单 元 没 有 释 放 前, 指 针 也 不 能 重 新 赋 值 ( 除 非 提 供 恢 复 该 指 针 初 值 的 方 法 ), 否 则 程 序 将 无 法 访 问 到 指 针 原 来 指 向 的 内 存 单 元, 也 没 有 办 法 释 放 它, 因 而 也 会 产 生 内 存 遗 漏 例 如 : int *p=new int; *p=2; p=new int; // 错 误, 产 生 内 存 遗 漏 就 因 为 指 针 在 原 来 指 向 的 内 存 单 元 没 有 释 放 前 被 重 新 赋 值, 从 而 造 成 了 原 指 向 的 内 存 遗 漏 如 果 改 成 下 面 的 形 式 就 是 正 确 的 : int *p=new int; * p=2; delete p; p=new int; 因 此, 在 程 序 中 对 应 于 每 次 使 用 运 算 符 new, 都 应 该 相 应 地 使 用 运 算 符 delete 来 释 放 申 请 的 内 存, 尽 管 有 时 确 实 是 多 余 的 另 外, 还 必 须 注 意 对 应 于 每 个 运 算 符 new, 只 能 调 用 一 次 delete 来 释 放 内 存 如 果 利 用 指 针 释 放 其 指 向 的 内 存 单 元 后, 没 有 对 这 个 指 针 再 次 调 用 new 来 使 之 指 向 其 他 有 效 内 存 就 进 行 delete 操 作, 有 可 能 导 致 程 序 崩 溃 不 过 对 空 指 针 调 用 delete 是 安 全 的, 因 此, 一 个 良 好 的 习 惯 是 每 次 delete 操 作 后, 给 相 应 的 指 针 赋 0 在 每 次 执 行 delete 操 作 后, 给 相 应 的 指 针 赋 0( 空 指 针 ) 可 以 避 免 丢 失 指 针 在 程 序 中 对 某 一 指 针 调 用 delete 后, 相 应 地 指 针 指 向 的 内 存 单 元 就 被 释 放, 但 指 针 的 值 ( 也 即 指 针 指 向 的 地 址 ) 并 没 改 变, 如 果 没 有 给 它 重 新 赋 值 就 使 用 该 指 针, 该 指 针 就 成 了 丢 失 指 针 因 为 编 译 器 有 可 能 已 经 把 这 个 内 存 单 元 重 新 分 配 出 去 了, 并 在 此 处 存 有 其 他 数 据 因 此, 错 误 地 使 用 该 指 针 也 有 可 能 导 致 程 序 崩 溃 其 实, 同 一 个 指 针 在 没 有 重 新 赋 值 的 情 况 下 多 次 调 用 delete 就 是 丢 失 指 针 的 情 形 之 一 例 6.14 动 态 内 存 分 配 的 演 示 #include"iostream.h" #include"stdlib.h" void main() int *p=new int; // 动 态 申 请 内 存 if(p==0) // 检 查 内 存 分 配 是 否 成 功 cout<<"error,menory allocation failure!"<<endl; exit(0); // 库 函 数, 用 于 终 止 程 序 的 运 行, 头 文 件 是 stdlib.h *p=10; cout<<"*p="<<*p<<endl; delete p; // 删 除 内 存
113 104 C++ 程 序 设 计 p=new int; // 重 新 申 请 内 存, 并 将 指 针 指 向 它 if (p==0) // 检 查 内 存 分 配 是 否 成 功 cout<<"error,menory allocation failure!"<<endl; exit(0); *p=20; cout<<"*p="<<*p<<endl; delete p; 运 行 程 序, 输 出 结 果 为 : *p=10 *p=20 在 这 个 例 子 中, 程 序 结 束 时 将 自 动 释 放 内 存, 因 此, 最 后 一 条 语 句 是 多 余 的 不 过, 加 上 它 是 一 个 好 的 习 惯 在 声 明 类 时, 类 中 的 数 据 成 员 也 可 以 是 指 向 堆 中 某 一 内 存 单 元 的 指 针, 内 存 单 元 可 以 由 构 造 函 数 分 配, 由 析 构 函 数 来 释 放 引 用 的 概 念 6.2 引 用 在 C++ 语 言 中, 提 供 了 一 种 为 变 量 起 一 个 别 名 的 机 制, 这 个 别 名 就 是 引 用 声 明 引 用 的 过 程 也 就 是 为 某 个 变 量 建 立 别 名 的 过 程 引 用 在 C++ 语 言 中 占 有 十 分 重 要 的 位 置, 对 引 用 施 加 的 任 何 操 作 实 际 上 都 施 加 在 引 用 所 代 表 的 变 量 上, 这 大 大 简 化 了 语 法, 使 原 来 一 些 难 于 处 理 的 问 题 得 到 解 决 使 用 引 用 进 行 编 程, 可 以 使 程 序 可 读 性 更 好, 使 用 也 更 方 便 引 用 声 明 的 一 般 格 式 如 下 : 数 据 类 型 & 引 用 名 = 变 量 名 ; 或 数 据 类 型 & 引 用 名 ( 变 量 名 ); 其 中, 数 据 类 型 是 指 被 引 用 变 量 的 类 型, 变 量 名 是 被 引 用 变 量 的 名 字, & 是 引 用 标 识 符, 被 引 用 的 变 量 可 以 是 任 一 类 型 的 变 量 例 如 : int a; int &b=a; 为 int 型 变 量 a 声 明 了 一 个 引 用 b 在 为 一 个 变 量 声 明 了 引 用 之 后, 引 用 就 成 了 这 个 变 量 的 别 名, 它 们 实 际 上 是 同 一 变 量 的 两 个 不 同 的 名 字, 在 内 存 中 代 表 同 一 块 存 储 区 域, 使 用 引 用 和 使 用 其 所 代 表 的 变 量 是 完 全 一 样 的 例 6.15 引 用 的 声 明 和 使 用 #include"iostream.h"
114 第 6 章 指 针 和 引 用 105 void main() int a=1; int &b=a; //b 是 变 量 a 的 引 用 cout<<"a="<<a<<endl; cout<<"b="<<b<<endl; b=2; // 对 b 赋 值 就 等 价 于 对 a 赋 值 cout<<"a="<<a<<endl; cout<<"b="<<b<<endl; cout<<"&a="<<&a<<endl; cout<<"&b="<<&b<<endl; 运 行 程 序, 将 输 出 结 果 : a=1 b=1 a=2 b=2 &a=0x0012f7c &b=0x0012f7c 这 个 例 子 中 的 最 后 两 条 语 句 是 输 出 变 量 的 地 址, 语 句 中 的 & 号 是 取 地 址 运 算 符, 不 要 与 引 用 标 识 符 混 淆 在 这 里, 还 可 以 发 现, 求 引 用 的 地 址, 实 际 上 返 回 的 是 被 引 用 变 量 的 地 址 这 也 进 一 步 证 明 了 引 用 是 被 引 用 变 量 的 别 名 任 何 变 量 都 可 以 被 引 用, 其 中 包 括 用 户 定 义 的 对 象 同 时, 需 要 注 意 的 是 引 用 初 始 化 后 其 值 不 能 改 变, 即 不 允 许 把 为 一 个 变 量 建 立 的 引 用 重 新 用 作 另 一 变 量 的 别 名 程 序 中 对 引 用 重 新 赋 值 的 作 用 是 给 被 引 用 变 量 赋 新 值 使 用 引 用 应 注 意 以 下 几 点 (1) 声 明 引 用 时, 除 了 引 用 作 为 函 数 参 数 或 返 回 引 用 的 函 数 这 两 种 情 况 外, 必 须 要 初 始 化 因 此, 赋 值 运 算 符 右 边 的 变 量 必 须 是 已 存 在 的 变 量, 即 必 须 先 定 义 变 量, 然 后 才 能 声 明 引 用 (2) 一 旦 为 一 个 变 量 声 明 了 一 个 引 用, 该 引 用 就 不 能 再 作 为 别 的 变 量 的 引 用 (3) 引 用 和 其 所 代 表 的 变 量 使 用 同 一 片 存 储 空 间, 它 并 不 另 外 占 用 存 储 空 间 引 用 与 函 数 1. 引 用 作 为 函 数 参 数 前 面 已 经 介 绍 了 以 指 针 作 为 函 数 的 参 数, 在 被 调 用 函 数 中 改 变 形 参 将 对 相 应 的 实 参 产 生 影 响 但 是, 如 果 在 函 数 中 反 复 利 用 指 针 进 行 间 接 访 问, 容 易 产 生 错 误 且 难 于 阅 读 C++ 语 言 还 提 供 了 采 用 引 用 作 为 函 数 参 数 的 方 法, 即 函 数 的 参 数 为 引 用 以 引 用 作 为 函 数 参 数 的 调 用 称 为 引 用 调 用 这 种 方 法 既 有 传 值 方 式 方 便 自 然 的 特 点, 又 有 传 址 方 式 能 更 新 实 参 值 的 长 处 例 6.16 利 用 引 用 作 为 函 数 参 数 改 写 例 6.11 的 程 序
115 106 C++ 程 序 设 计 #include"iostream.h" void swap(int &a,int &b); void main() int x=1,y=2; cout<<" 交 换 前 "<<endl; cout<<"x="<<x<<",y="<<y<<endl; swap(x,y); cout<<" 交 换 后 "<<endl; cout<<"x="<<x<<",y="<<y<<endl; void swap(int &a,int &b) int temp; temp=a; a=b; b=temp; 运 行 程 序, 输 出 结 果 与 例 6.11 完 全 一 样 由 此 可 以 看 出, 通 过 将 引 用 作 为 函 数 参 数, 被 调 用 函 数 可 以 改 变 主 调 函 数 中 实 参 的 值, 引 用 调 用 完 全 可 以 实 现 传 址 调 用 的 功 能, 而 且 使 用 起 来 像 普 通 变 量 一 样, 维 护 也 非 常 方 便 注 意 : 实 参 前 没 有 引 用 运 算 符 & 2. 返 回 引 用 的 函 数 函 数 的 返 回 值 可 以 是 引 用, 其 一 般 形 式 为 : 数 据 类 型 & 函 数 名 ( 形 参 表 ) 若 函 数 的 返 回 值 类 型 为 引 用, 可 以 通 过 对 函 数 赋 值, 实 现 对 函 数 返 回 的 引 用 的 赋 值 例 6.17 返 回 引 用 的 函 数 #include"iostream.h" int temp; int &max(int x,int y) if(x>y) temp=x;else temp=y; return temp; void main() int a=max(15,25); cout<<"a="<<a<<",temp="<<temp<<endl; max(15,25)=50; // 实 现 对 max() 函 数 的 返 回 值 temp 的 赋 值
116 第 6 章 指 针 和 引 用 107 cout<<"temp="<<temp<<endl; 运 行 程 序, 将 输 出 结 果 : a=25,temp=25 temp=50 上 面 的 程 序 中, 对 函 数 max() 的 赋 值 就 是 对 函 数 返 回 的 引 用 类 型 变 量 temp 的 赋 值 注 意 : 在 使 用 返 回 引 用 的 函 数 时,return 语 句 的 返 回 值 通 常 为 全 局 变 量 或 静 态 变 量, 否 则 有 可 能 当 函 数 调 用 结 束 时, 变 量 的 作 用 域 消 失, 从 而 造 成 错 误 通 过 以 上 的 分 析, 可 能 读 者 已 经 发 现 指 针 可 以 实 现 的 功 能, 大 部 分 都 能 用 引 用 替 代, 而 且 引 用 更 容 易 使 用, 更 清 晰 因 此, 用 户 在 编 程 时, 应 该 多 采 用 引 用, 少 采 用 指 针 不 过, 指 针 能 实 现 引 用 的 全 部 功 能, 但 引 用 却 无 法 完 全 替 代 指 针 首 先, 引 用 不 可 以 是 空 引 用 引 用 空 对 象 在 程 序 中 是 错 误 的, 有 可 能 导 致 严 重 的 后 果 不 过, 多 数 编 译 器 并 不 认 为 它 是 一 种 错 误, 只 有 在 程 序 中 试 图 以 某 种 方 式 处 理 空 引 用 时 才 可 能 引 起 系 统 崩 溃 因 此, 如 果 对 象 有 可 能 为 空 时, 就 必 须 采 用 指 针 其 次, 引 用 是 常 量, 不 能 重 新 赋 值 如 果 程 序 需 要 先 指 向 一 个 对 象, 后 又 指 向 另 一 对 象, 此 时 应 该 采 用 指 针 习 题 1. 如 果 正 常 执 行 了 如 下 语 句 : int m[22],*p1=&m[4],*p2=m+15,x; x=p2 p1 则 x 的 值 为 ( ) 2. 如 果 正 常 执 行 了 如 下 语 句 : int d[]=1,2,3,4,5,6,7,8,9,10.*p1=d+8,*p2=&m[3]; p1 =3 cout<<*p1<<'\t'<<*p2; 则 程 序 的 输 出 为 ( ) 3. 已 知 数 组 x 定 义 为 int x[10], 并 能 顺 利 执 行 语 句 p1=x, 则 p1 的 声 明 语 句 为 ( ) 4. 已 知 数 组 y 定 义 为 int y[5], 并 能 顺 利 执 行 语 句 p2=&y, 则 p2 的 声 明 语 句 为 ( ) 5. 分 析 下 面 程 序 的 运 行 结 果 #include"iostream.h" void main() int a=10; int *p1=&a; int *&p2=p1; cout<<"a="<<a<<",*p1="<<*p1<<",*p2="<<*p2; 6. 分 析 下 面 程 序 的 运 行 结 果
117 108 C++ 程 序 设 计 #include"iostream.h" void main() int x=100; int &x1=x; int y=200; int &y1=y; cout<<"x="<<x<<",x1="<<x1<<endl; cout<<"y="<<y<<",y1="<<y1<<endl; x1+=20; y1/=8; cout<<"x="<<x<<",x1="<<x1<<endl; cout<<"y="<<y<<",y1="<<y1<<endl; 7. 设 有 一 个 整 型 数 组, 有 10 个 元 素, 请 用 3 种 不 同 的 方 法 输 出 各 元 素 8. 假 设 有 一 个 字 符 串 str1, 其 内 容 为 "Hello! ", 请 利 用 指 针 将 该 字 符 串 的 内 容 复 制 到 另 一 个 字 符 串 str2 中 9. 输 入 两 个 字 符 串, 将 它 们 排 序, 然 后 输 出 这 10 个 已 排 好 序 的 字 符 串 编 写 3 个 函 数 分 别 用 于 输 入 排 序 和 输 出, 并 在 main() 函 数 中 调 用 它 们 10. 编 写 程 序, 将 输 入 字 符 串 中 的 大 写 字 母 转 换 为 小 写 字 母, 并 显 示 输 出 11. 输 入 一 个 字 符 串, 然 后 将 它 们 逆 序 输 出 例 如 : 输 入 "abcd", 输 出 "dcba"
118 第 7 章 类 与 数 据 抽 象 在 面 向 对 象 程 序 设 计 中, 最 基 本 的 概 念 是 类 和 对 象, 类 的 基 本 特 征 有 封 装 性 继 承 性 和 多 态 性 类 是 实 现 抽 象 数 据 类 型 的 工 具, 是 对 某 一 类 具 有 相 同 特 性 对 象 的 抽 象 它 不 仅 定 义 了 数 据 的 类 型, 同 时 也 定 义 了 对 数 据 的 操 作 类 中 的 成 员, 根 据 访 问 权 限 可 分 为 3 类 : 私 有 保 护 和 公 有 对 象 是 某 个 类 的 实 例, 类 和 对 象 是 紧 密 相 关 的 7.1 类 的 定 义 类 是 一 种 复 杂 的 数 据 类 型, 它 是 将 不 同 类 型 的 数 据 和 与 这 些 数 据 相 关 的 操 作 封 装 在 一 起 的 集 合 体, 有 点 像 C 语 言 中 的 结 构 体 惟 一 不 同 的 就 是 结 构 体 没 有 类 的 定 义 所 说 的 数 据 相 关 的 操 作, 数 据 相 关 的 操 作 就 是 平 常 看 到 的 方 法 因 此, 类 具 有 更 高 的 抽 象 性, 类 中 的 数 据 具 有 信 息 隐 藏 性, 类 还 具 有 封 装 性 类 的 结 构 ( 即 类 的 组 成 ) 用 来 确 定 一 类 对 象 的 行 为, 而 这 些 行 为 是 通 过 类 的 内 部 数 据 结 构 和 相 关 的 操 作 来 确 定 的 这 些 行 为 是 通 过 一 种 操 作 接 口 ( 即 平 时 所 看 到 的 类 的 成 员 函 数 ) 来 描 述 的, 使 用 者 关 心 的 只 是 接 口 的 功 能, 即 只 关 心 类 的 各 个 成 员 函 数 的 功 能, 对 它 是 如 何 实 现 的 并 不 感 兴 趣 操 作 接 口 又 被 称 为 这 类 对 象 向 其 他 对 象 所 提 供 的 服 务 类 的 定 义 格 式 一 般 分 为 说 明 部 分 和 实 现 部 分 说 明 部 分 用 来 说 明 该 类 中 的 成 员, 包 括 数 据 成 员 的 说 明 和 成 员 函 数 的 说 明 成 员 函 数 是 用 来 对 数 据 成 员 进 行 操 作 的, 又 称 为 方 法 公 有 成 员 函 数 是 用 户 使 用 类 的 界 面 或 接 口 实 现 部 分 是 用 来 定 义 成 员 函 数 具 体 功 能 的, 说 明 类 成 员 函 数 的 功 能 是 如 何 实 现 的 类 的 一 般 定 义 格 式 如 下 : class < 类 名 > public: < 数 据 成 员 或 成 员 函 数 的 说 明 > private: < 数 据 成 员 或 成 员 函 数 的 说 明 > ; < 各 个 成 员 函 数 的 实 现 > 其 中,class 是 定 义 类 的 关 键 字,< 类 名 > 是 符 合 C++ 规 定 的 标 识 符 花 括 号 内 部 是 类 的 说 明 部 分 ( 包 括 前 面 的 类 头 ), 用 来 说 明 该 类 的 成 员 类 的 成 员 包 含 数 据 成 员 和 成 员 函 数 两 部 分 从 访 问 权 限 上 来 分, 类 的 成 员 又 分 为 : 公 有 的 (public) 私 有 的 (private) 和 保 护 的 (protected)3 类
119 110 C++ 程 序 设 计 公 有 的 成 员 用 public 来 说 明, 公 有 部 分 往 往 是 一 些 操 作 ( 即 成 员 函 数 ), 它 是 提 供 给 用 户 的 接 口 功 能 这 部 分 成 员 可 以 在 程 序 中 引 用 私 有 的 成 员 用 private 来 说 明, 私 有 部 分 通 常 是 一 些 数 据 成 员, 这 些 成 员 用 来 描 述 该 类 中 的 对 象 的 属 性, 用 户 是 无 法 访 问 它 们 的, 只 有 成 员 函 数 或 经 特 殊 说 明 的 函 数 才 可 以 引 用 它 们, 它 们 是 被 用 来 隐 藏 的 部 分 保 护 的 (protected) 成 员 将 在 第 9 章 中 详 细 介 绍 关 键 字 public,private 和 protected 被 称 为 访 问 权 限 修 饰 符 或 访 问 控 制 修 饰 符 它 们 在 类 体 内 ( 即 一 对 花 括 号 内 ) 出 现 的 先 后 顺 序 无 关, 并 且 允 许 多 次 出 现, 用 它 们 来 说 明 类 成 员 的 访 问 权 限 < 各 个 成 员 函 数 的 实 现 > 是 类 定 义 中 成 员 函 数 具 体 功 能 的 实 现 部 分, 这 部 分 包 含 所 有 在 类 体 内 说 明 函 数 的 具 体 功 能 如 果 一 个 成 员 函 数 在 定 义 时 实 现 了 它 的 具 体 功 能, 实 现 部 分 将 不 出 现 如 果 所 有 的 成 员 函 数 的 功 能 都 在 定 义 时 实 现 了 ( 即 在 类 体 内 的 定 义 部 分 实 现 其 功 能 ), 则 在 类 体 外 的 实 现 部 分 可 以 省 略 例 7.1 下 面 给 出 一 个 关 于 时 间 的 类 的 定 义, 该 类 是 对 时 间 的 抽 象, 该 类 的 对 象 将 是 一 个 具 体 的 时 间 // 类 的 说 明 部 分 : class Time private: int hour; int minute; int second; public: Time(); void SetTime(int,int,int); void printmilitary(); void printstandard(); ; // 类 的 实 现 部 分 Time::Time() hour= minute = second =0; void Time::SetTime(int h, int m, int s) hour = (h>=0&&h<24)?h:0; minute = (m>=0&&m<60)?m:0; second = (s>=0&&m<60)?s:0; void Time::PrintMilitary() cout<<(hour<10? "0": "")<<hour<<":"<<(minute<10? "0": "")<< minute <<endl; void Time::PrintStandard()
120 第 7 章 类 与 数 据 抽 象 111 cout<<(hour==0 hour==12? 12: hour%12)<< ":"<<(minute<10? "0": "")<< minute << ":"<<(second<10? "0": "")<< second<<(hour<12? " AM": " PM")<<endl; 这 里 出 现 的 作 用 域 运 算 符 :: 是 用 来 标 识 某 个 成 员 函 数 是 属 于 哪 个 类 的 Time 类 在 定 义 时 还 可 以 将 成 员 函 数 的 实 现 部 分 ( 即 函 数 的 定 义 ) 放 在 类 体 内, 写 成 如 下 形 式 : class Time private: int hour; int minute; int second; public: Time() hour= minute = second =0; void SetTime(int h, int m, int s) hour =(h>=0&&h<24)?h:0; minute =(m>=0&&m<60)?m:0; second =(s>=0&&m<60)?s:0; void PrintMilitary() cout<<(hour<10? "0": "")<<hour<<":"<<(minute<10? "0": "")<<minute <<endl; void Time::PrintStandard() cout<<(hour==0 hour==12?12: hour%12)<< ":"<<(minute<10? "0": "")<< minute << ":"<<(second<10? "0": "")<<second<<(hour<12? " AM": " PM")<<endl; ; 如 果 成 员 函 数 定 义 在 类 体 外, 则 在 函 数 头 的 前 面 必 须 加 上 作 用 域 运 算 符 ::, 以 表 明 该 函 数 所 属 类 的 标 识 在 定 义 类 时 应 注 意 以 下 几 点 (1) 在 类 体 中 不 允 许 对 所 定 义 的 数 据 成 员 进 行 初 始 化 (2) 类 中 的 数 据 成 员 的 类 型 可 以 是 任 意 的, 包 括 基 本 类 型 数 组 指 针 和 引 用 等 也 可 以 是 对 象 另 一 个 类 的 对 象, 可 以 作 该 类 的 成 员, 但 是 自 身 类 的 对 象 是 不 可 以 的, 而 自 身 类 的 指 针 或 引 用 是 可 以 的 当 A 类 的 对 象 作 为 B 类 的 成 员 时, 如 果 A 类 的 定 义 在 后, 则 需 要 提 前 说 明 (3) 经 常 习 惯 地 将 类 定 义 的 说 明 部 分 或 者 整 个 定 义 部 分 ( 包 含 实 现 部 分 ) 放 到 一 个 头 文 件 中
121 112 C++ 程 序 设 计 对 象 的 定 义 7.2 对 象 的 定 义 前 面 已 经 提 到, 对 象 是 类 的 实 例, 它 一 定 属 于 某 个 已 知 的 类 因 此, 定 义 对 象 之 前, 一 定 要 先 定 义 好 该 对 象 的 类 对 象 定 义 的 一 般 格 式 为 : < 类 名 > < 对 象 名 表 > 其 中,< 类 名 > 是 要 定 义 对 象 所 属 类 的 名 字, 即 所 定 义 的 对 象 是 该 类 类 型 的 对 象 < 对 象 名 表 > 中 可 以 有 一 个 或 多 个 对 象 名, 多 个 对 象 名 时 用 逗 号 分 隔 < 对 象 名 表 > 中 可 以 是 一 般 的 对 象 名, 还 可 以 是 指 向 对 象 的 指 针 名 或 引 用 名, 也 可 以 是 对 象 数 组 名 例 如 : Time t1,*t2,t3[3]; 对 象 成 员 的 表 示 方 法 一 个 对 象 的 成 员 就 是 该 对 象 的 类 所 定 义 的 成 员 对 象 成 员 有 数 据 成 员 和 成 员 函 数, 其 表 示 方 式 如 下 : < 对 象 名 >.< 成 员 名 > 或 者 为 : < 对 象 名 >.< 成 员 名 >(< 参 数 表 >) 前 者 用 来 表 示 数 据 成 员, 后 者 用 来 表 示 成 员 函 数 如 : t1.hour, t1.minute, t1.second; t1.settime(6,10,18); 这 里,. 是 一 个 运 算 符, 该 运 算 符 的 功 能 是 表 示 对 象 的 成 员 例 7.2 下 面 给 出 一 个 日 期 类 的 例 子 #include "iostream.h" class Date public: void SetDate(int y, int m, int d); int IsLeapYear(); void Print(); private: int year, month, day; ; // 类 的 实 现 部 分 void Date::SetDate(int y, int m, int d) year = y;
122 第 7 章 类 与 数 据 抽 象 113 month = m; day = d; int Date::IsLeapYear() return(year%4==0 && year%100!=0) (year%400==0); void Date::Print() cout<<year<<"."<<month<<"."<<day<<endl; void main() Date today,tomorrow; today.setdate (2004,2,15); cout<<"today is:"; today.print(); tomorrow.setdate (2004,2,16); cout<<"tomorrow is:"; tomorrow.print(); if(today.isleapyear()) cout<<"this year is Leap Year.\n"; else cout<<"this year is not Leap Year.\n"; 运 行 结 果 为 : Today is: Tomorrow is: This year is Leap Year. 由 同 一 个 类 所 创 建 的 对 象 的 数 据 结 构 是 相 同 的, 类 中 的 成 员 函 数 是 共 享 的 两 个 不 同 的 对 象, 其 名 字 是 不 同 的, 它 们 的 数 据 结 构 的 内 容 ( 即 数 据 成 员 的 值 ) 也 是 不 同 的 因 此, 系 统 对 已 定 义 的 对 象 仅 给 它 们 分 配 数 据 成 员 变 量, 而 一 般 情 况 下 数 据 成 员 都 是 私 有 的 成 员 不 同 对 象 的 数 据 成 员 的 值 可 以 是 不 相 同 的 7.3 构 造 函 数 和 析 构 函 数 构 造 函 数 和 析 构 函 数 1. 构 造 函 数 构 造 函 数 是 一 个 特 殊 的 成 员 函 数 构 造 函 数 的 功 能 是 在 创 建 对 象 时, 使 用 给 定 的 值 将 对 象
123 114 C++ 程 序 设 计 初 始 化 该 函 数 的 名 字 与 类 名 相 同, 不 指 定 类 型 说 明, 它 有 隐 含 的 返 回 值, 该 值 由 系 统 内 部 使 用 该 函 数 可 以 有 一 个 参 数, 也 可 以 有 多 个 参 数, 即 构 造 函 数 可 以 重 载 函 数 体 可 以 写 在 类 体 内, 也 可 以 写 在 类 体 外 程 序 中 不 能 直 接 调 用 构 造 函 数, 在 创 建 对 象 时 系 统 自 动 调 用 构 造 函 数 例 7.3 构 造 函 数 应 用 举 例 class Date public: Date(int y); Date(int y, int m) year= y;month=m;day=0; Date(int y, int m, int d); int IsLeapYear(); void Print(); private: int year, month, day; ; // 类 的 实 现 部 分 Date::Date(int y) year= y;month=day=0; cout<<"1 个 参 数 的 构 造 函 数 已 被 调 用 \n"; Date::Date(int y, int m) year= y;month=m;day=0; cout<<"2 个 参 数 的 构 造 函 数 已 被 调 用 \n"; Date:: Date(int y, int m, int d) year = y; month = m; day = d; cout<<"3 个 参 数 的 构 造 函 数 已 被 调 用 \n"; int Date::IsLeapYear() return(year%4==0 && year%100!=0) (year%400==0); void Date::Print()
124 第 7 章 类 与 数 据 抽 象 115 cout<<year<<"."<<month<<"."<<day<<endl; 2. 析 构 函 数 析 构 函 数 也 是 一 个 特 殊 的 函 数, 其 功 能 与 构 造 函 数 的 功 能 正 好 相 反, 是 用 来 释 放 一 个 对 象, 在 对 象 删 除 前, 用 它 来 做 一 些 清 理 工 作 析 构 函 数 的 名 字 与 类 名 相 同, 并 在 前 面 加 上 ~ 字 符, 用 来 与 构 造 函 数 加 以 区 别 析 构 函 数 不 指 定 数 据 类 型, 也 没 有 参 数 一 个 类 中 只 能 定 义 一 个 析 构 函 数 析 构 函 数 是 成 员 函 数, 函 数 体 可 写 在 类 体 内, 也 可 写 在 类 体 外 析 构 函 数 可 以 被 调 用, 也 可 以 被 系 统 调 用 在 下 面 两 种 情 况 下, 析 构 函 数 会 被 系 统 自 动 调 用 (1) 如 果 一 个 对 象 被 定 义 在 一 个 函 数 体 内, 则 当 这 个 函 数 结 束 时, 该 对 象 的 析 构 函 数 被 自 动 调 用 (2) 当 一 个 对 象 是 使 用 new 运 算 符 动 态 创 建 的, 在 使 用 delete 运 算 符 释 放 它 时,delete 将 会 自 动 调 用 析 构 函 数 例 7.4 下 面 程 序 说 明 构 造 函 数 和 析 构 函 数 的 应 用 #include "iostream.h" class Date public: Date(int y=0, int m=0, int d=0); ~Date(); int IsLeapYear(); void Print(); private: int year, month, day; ; // 类 的 实 现 部 分 Date:: Date(int y, int m, int d) year = y; month = m; day = d; cout<<" 构 造 函 数 已 被 调 用 \n"; Date::~ Date() cout<<" 析 构 函 数 被 调 用 \n"; int Date::IsLeapYear()
125 116 C++ 程 序 设 计 return(year%4==0 && year%100!=0) (year%400==0); void Date::Print() cout<<year<<"."<<month<<"."<<day<<endl; void main() Date today(2004, 3, 15), tomorrow(2004, 3, 16); cout<<"today is:"; today.print(); cout<<"tomorrow is:"; tomorrow.print(); 运 行 结 果 为 : 构 造 函 数 已 被 调 用 构 造 函 数 已 被 调 用 Today is: Tomorrow is: 析 构 函 数 被 调 用 析 构 函 数 被 调 用 缺 省 构 造 函 数 和 缺 省 析 构 函 数 在 类 定 义 时 没 有 定 义 任 何 构 造 函 数 时, 则 编 译 器 会 自 动 生 成 一 个 不 带 参 数 的 缺 省 构 造 函 数, 其 格 式 如 下 : < 类 名 >::< 缺 省 构 造 函 数 名 >() 缺 省 构 造 函 数 名 和 类 名 相 同 缺 省 构 造 函 数 也 可 由 程 序 员 定 义 在 类 体 中 在 程 序 中 定 义 一 个 对 象 而 没 有 进 行 初 始 化 时, 则 编 译 器 便 按 缺 省 构 造 函 数 来 初 始 化 该 对 象 用 缺 省 构 造 函 数 初 始 化 对 象 时, 对 象 的 所 有 数 据 成 员 都 初 始 化 为 零 或 空 同 理, 如 果 一 个 类 中 没 有 定 义 析 构 函 数 时, 则 编 译 系 统 也 生 成 一 个 缺 省 析 构 函 数, 其 格 式 如 下 : < 类 名 >::~< 缺 省 析 构 函 数 名 > 缺 省 析 构 函 数 是 一 个 空 函 数
126 第 7 章 类 与 数 据 抽 象 拷 贝 初 始 化 构 造 函 数 拷 贝 初 始 化 构 造 函 数 是 一 种 特 殊 的 成 员 函 数, 它 的 功 能 是 用 一 个 已 知 的 对 象 来 初 始 化 一 个 被 创 建 的 同 类 的 对 象 拷 贝 初 始 化 构 造 函 数 实 际 上 也 是 构 造 函 数, 它 是 在 初 始 化 时 用 来 将 一 个 已 知 对 象 的 数 据 成 员 的 值 拷 贝 给 正 在 创 建 的 另 一 个 同 类 的 对 象 拷 贝 初 始 化 构 造 函 数 的 特 点 如 下 (1) 该 函 数 名 与 类 名 相 同, 因 为 它 也 是 一 种 构 造 函 数, 并 且 该 函 数 不 被 指 定 返 回 类 型 (2) 该 函 数 只 有 一 个 参 数, 并 且 是 对 某 个 对 象 的 引 用 (3) 每 个 类 都 必 须 有 一 个 拷 贝 初 始 化 构 造 函 数 拷 贝 初 始 化 构 造 函 数 格 式 如 下 : < 类 名 >::< 拷 贝 初 始 化 构 造 函 数 名 >(const < 类 名 >& < 引 用 名 >) 其 中,< 拷 贝 初 始 化 构 造 函 数 名 > 与 该 类 名 相 同 const 是 一 个 类 型 修 饰 符, 被 它 修 饰 的 对 象 是 一 个 不 能 被 更 新 的 常 量 如 果 类 中 没 有 说 明 拷 贝 初 始 化 构 造 函 数, 则 编 译 系 统 自 动 生 成 一 个 具 有 上 述 形 式 的 缺 省 拷 贝 初 始 化 构 造 函 数, 作 为 该 类 的 公 有 成 员 拷 贝 初 始 化 构 造 函 数 的 功 能 就 是 用 一 个 已 知 的 对 象 来 初 始 化 另 一 个 对 象 在 下 述 3 种 情 况 下, 需 要 用 拷 贝 初 始 化 构 造 函 数 来 用 一 个 对 象 初 始 化 另 一 个 对 象 (1) 明 确 表 示 由 一 个 对 象 初 始 化 另 一 个 对 象 时, 如 TPoint P2(P1) (2) 当 对 象 作 为 函 数 实 参 传 递 给 函 数 形 参 时, 如 上 例 中 的 P = f(n) (3) 当 对 象 用 作 函 数 返 回 值 时, 如 上 例 中 的 return R 例 7.5 拷 贝 初 始 化 构 造 函 数 应 用 举 例 #include "iostream.h" class Tpoint public: TPoint(int x, int y) X=x; Y=y; TPoint(TPoint & p); ~TPoint() cout<<" 析 构 函 数 被 调 用 \n"; int Xcoord() return X; int Ycoord() return Y; private: int X, Y; ; TPoint::TPoint(TPoint & p) X = p.x; Y = p.y; cout<<" 拷 贝 初 始 化 构 造 函 数 被 调 用 \n";
127 118 C++ 程 序 设 计 void main() TPoint P1(5, 7); TPoint P2(P1); cout<<"p2="<<p2.xcoord()<<","<<p2.ycoord()<<endl; 运 行 程 序, 输 出 结 果 为 : 拷 贝 初 始 化 构 造 函 数 被 调 用 P2=5,7 析 构 函 数 被 调 用 析 构 函 数 被 调 用 例 7.6 关 于 拷 贝 初 始 化 构 造 函 数 的 其 他 用 法 #include "iostream.h" class TPoint public: TPoint(int x,int y) X=x;Y=y; TPoint(TPoint &p); ~TPoint() cout<<" 析 构 函 数 被 调 用 \n"; int Xcoord() return X; int Ycoord() return Y; private: int X,Y; ; TPoint::TPoint(TPoint & p) X = p.x; Y = p.y; cout<<" 拷 贝 初 始 化 构 造 函 数 被 调 用 \n"; TPoint f(tpoint Q); void main() TPoint M(20, 35),P(0, 0); TPoint N(M); P = f(n); cout<<"p="<<p.xcoord()<<","<<p.ycoord()<<endl;
128 第 7 章 类 与 数 据 抽 象 119 TPoint f(tpoint Q) cout<<"ok\n"; int x, y; x = Q.Xcoord()+25; y= Q.Ycoord()+30; TPoint R(x, y); return R; 运 行 程 序, 输 出 结 果 如 下 : 拷 贝 初 始 化 构 造 函 数 被 调 用 拷 贝 初 始 化 构 造 函 数 被 调 用 ok 拷 贝 初 始 化 构 造 函 数 被 调 用 析 构 函 数 被 调 用 析 构 函 数 被 调 用 析 构 函 数 被 调 用 P=45,65 析 构 函 数 被 调 用 析 构 函 数 被 调 用 析 构 函 数 被 调 用 7.4 成 员 函 数 的 特 征 成 员 函 数 的 重 载 类 的 成 员 函 数 同 普 通 函 数 一 样 也 可 以 进 行 重 载 例 7.7 成 员 函 数 重 载 应 用 举 例 #include "iostream.h" class myclass private: int x; int y; int z; public: void set()x=10;y=20;z=30; void set(int xx)x=xx;y=20;z=30; void set(int xx,int yy )x=xx;y=yy;z=30;
129 120 C++ 程 序 设 计 void set(int xx,int yy,int zz) x=xx;y=yy;z=zz; void print()cout<< x<<'\t'<< y<<'\t'<< z<<'\n'; ; void main() myclass b1; cout <<"x y z\n"; b1.set (); b1.print (); b1.set (11); b1.print (); b1.set (11,22); b1.print (); b1.set (11,22,33); b1.print (); 运 行 结 果 : x y z 在 上 面 的 程 序 中, 声 明 了 一 个 名 为 myclass 的 类, 它 包 含 3 个 整 型 的 私 有 变 量 它 有 一 个 重 载 的 公 有 成 员 函 数, 用 于 设 置 私 有 变 量 的 值 函 数 调 用 时 会 根 据 实 参 的 类 型 和 个 数 调 用 相 应 的 成 员 函 数 在 main() 中 进 行 了 4 次 调 用 : b1.set (),b1.set (11),b1.set (11,22) 和 b1.set (11,22,33) 第 一 次 调 用 时, 调 用 的 是 无 参 的 成 员 函 数 ; 第 二 次 调 用 仅 有 一 个 实 参, 调 用 的 是 一 个 形 参 的 成 员 函 数 ; 第 三 次 函 数 调 用 有 两 个 实 参, 调 用 的 是 两 个 形 参 的 成 员 函 数 ; 第 四 次 函 数 调 用 有 3 个 实 参, 调 用 的 是 3 个 形 参 的 成 员 函 数 参 数 的 缺 省 值 可 以 在 调 用 函 数 时 不 指 定 所 有 参 数 为 了 运 行 此 函 数, 对 于 没 有 在 函 数 调 用 中 指 定 的 参 数, 函 数 声 明 时 必 须 设 定 其 默 认 值 例 7.8 计 算 盒 子 的 体 积 程 序 如 下 #include"iostream.h" class Box private: int length; int width;
130 第 7 章 类 与 数 据 抽 象 121 int height; public: int get_volume(int length,int width = 2,int height = 3); ; int Box::get_volume(int l, int w, int h) length = l; width = w; height = h; cout<< length<<'\t'<< width<<'\t'<< height<<'\t'; return length*width*height; void main() Box b1; int x = 6, y = 8, z = 10; cout <<"Length Width Height Volume\n"; cout << b1.get_volume(x, y, z) << "\n"; cout << b1.get_volume(x, y) << "\n"; cout << b1.get_volume(x) << "\n"; cout << b1.get_volume(x, 9) << "\n"; cout << b1.get_volume(6, 6, 6) << "\n"; 运 行 程 序, 输 出 结 果 为 : Length Width Height Volume 在 例 7.8 中, 声 明 了 一 个 名 为 Box 的 类, 它 含 有 3 个 私 有 的 整 型 变 量 和 一 个 公 有 的 成 员 函 数, 已 为 其 参 数 设 定 了 默 认 值 : int get_volume(int length,int width = 2,int height = 3); 从 函 数 get_volume() 的 声 明 中, 第 一 个 名 为 length 的 参 数 对 于 每 次 函 数 调 用 必 须 给 出, 因 为 没 有 提 供 默 认 值 然 而, 并 不 需 要 为 每 个 函 数 调 用 指 定 第 二 个 名 为 width 的 参 数, 如 果 没 有 指 定 它, 将 把 值 2 用 于 函 数 中 的 变 量 width 同 样 地, 第 三 个 参 数 也 是 可 选 的, 如 果 它 没 有 指 定, 在 函 数 中, 将 把 值 3 赋 给 height
131 122 C++ 程 序 设 计 7.5 静 态 成 员 静 态 数 据 成 员 在 定 义 一 个 类 时, 可 以 使 用 static 关 键 字 指 定 静 态 成 员, 包 括 静 态 数 据 成 员 和 静 态 成 员 函 数 静 态 数 据 成 员 的 使 用 同 静 态 变 量 一 样, 只 是 在 创 建 第 一 个 对 象 时, 系 统 为 该 成 员 分 配 相 应 的 存 储 空 间 并 进 行 初 始 化, 这 在 类 的 所 有 对 象 或 部 分 对 象 需 要 共 享 某 些 相 同 的 信 息 时 是 很 有 用 处 的 例 7.9 静 态 数 据 成 员 使 用 举 例 此 程 序 用 于 计 算 并 显 示 矩 形 的 面 积, 还 将 显 示 每 次 由 对 象 递 增 的 静 态 数 据 成 员 的 值 #include"iostream.h" class rectangle private: int length; int width; static int extra_data; // 声 明 静 态 成 员 extra_data public: rectangle(); void set(int new_length, int new_width); int get_area(); int get_extra(); ; int rectangle::extra_data; // 定 义 静 态 成 员 变 量 extra_data rectangle::rectangle() length = 8; width = 8; extra_data = 1; void rectangle::set(int new_length,int new_width) length = new_length; width = new_width; int rectangle::get_area()
132 第 7 章 类 与 数 据 抽 象 123 return (length * width); int rectangle::get_extra() return extra_data++; void main() rectangle small, medium, large; small.set(5, 7); large.set(15, 20); cout<<"small rectangle area is "<<small.get_area()<<"\n"; cout<<"medium rectangle area is "<<medium.get_area()<<"\n"; cout<<"large rectangle area is "<<large.get_area()<<"\n"; cout <<"The static data value is "<<small.get_extra()<<"\n"; cout <<"The static data value is "<<medium.get_extra()<<"\n"; cout <<"The static data value is "<<large.get_extra()<<"\n"; 运 行 程 序, 输 出 结 果 为 : Small rectangle area is 35 Medium rectangle area is 64 Large rectangle area is 300 The static data value is 1 The static data value is 2 The static data value is 3 在 类 rectangle 中, 除 私 有 数 据 成 员 length 和 width 外, 还 包 括 数 据 成 员 extra_data 由 于 用 关 键 字 static 来 声 明 此 变 量, 故 此 变 量 有 一 个 副 本 在 程 序 运 行 期 间 永 远 存 在, 该 类 的 所 有 对 象 共 享 此 变 量 的 副 本 该 变 量 在 此 处 加 以 声 明, 表 明 该 变 量 将 存 在 并 赋 予 它 一 个 名 称, 但 尚 未 定 义 所 以, 在 类 rectangle 中 实 际 是 定 义 一 个 位 置, 以 将 其 存 储 于 计 算 机 内 存 空 间 中 的 某 处 静 态 数 据 成 员 能 在 类 说 明 符 中 声 明, 但 不 能 在 其 中 定 义 在 例 7.9 中 可 以 看 到, 静 态 成 员 变 量 的 定 义 紧 接 在 类 说 明 符 之 后 对 于 静 态 数 据 成 员 的 初 始 化 不 能 在 构 造 函 数 中 进 行 因 为 构 造 函 数 将 被 调 用 多 次, 而 静 态 函 数 成 员 只 能 初 始 化 一 次 因 此, 一 个 静 态 函 数 成 员 只 能 像 全 局 变 量 一 样 在 属 于 全 局 范 围 的 类 别 说 明 后, 在 全 局 范 围 中 进 行 初 始 化, 然 后 才 能 使 用 构 造 函 数 在 每 次 创 建 对 象 时 都 将 静 态 变 量 extra_data 设 为 1 仅 需 一 次 赋 值, 所 以 其 他 两 次 实 际 上 是 无 用 代 码 通 常, 在 构 造 函 数 中 为 静 态 成 员 赋 值 并 不 是 很 理 想 的 做 法 但 是, 在 此 例 中, 将 其 包 括 在 内 只 是 为 了 显 示 静 态 变 量 是 如 何 起 作 用 的 构 造 函 数 还 将 值 8 赋 给 类 的 数 据 成 员 length 和 width 为 了 表 明 此 类 的 所 有 对 象 仅 共 享 一 个 变 量, 用 于 返 回 静 态 变 量 值 的 函 数 extra_data() 也 使 变
133 124 C++ 程 序 设 计 量 的 值 加 1 对 象 每 次 调 用 extra_data() 时, 静 态 变 量 值 加 1 运 行 程 序 显 示 的 执 行 结 果 表 明, 仅 有 一 个 变 量 由 此 类 的 所 有 对 象 共 享 函 数 set() 获 取 类 型 为 int 的 两 个 参 数, 并 将 它 们 的 值 赋 给 数 据 成 员 length 和 width 在 main() 中 要 设 置 两 次 函 数 调 用, 这 两 次 调 用 将 值 赋 给 对 象 small 和 large 的 数 据 成 员 调 用 构 造 函 数 时, 对 象 medium 使 用 赋 给 数 据 成 员 的 值 函 数 get_area() 计 算 矩 形 的 面 积, 返 回 值 在 输 出 结 果 中 显 示 静 态 成 员 函 数 类 的 成 员 函 数 也 可 以 是 静 态 的 当 一 个 函 数 不 需 要 访 问 类 中 除 静 态 数 据 成 员 之 外 的 数 据 时, 我 们 可 以 将 其 定 义 为 静 态 成 员 函 数 一 般 情 况 下, 静 态 成 员 函 数 只 能 访 问 类 中 的 静 态 数 据 成 员 静 态 成 员 函 数 是 被 一 个 类 中 所 有 对 象 共 享 的 成 员 函 数, 不 属 于 哪 个 特 定 的 对 象 例 7.10 在 下 面 的 程 序 中, 将 使 用 类 Car 为 自 己 的 每 一 个 对 象 提 供 了 对 象 ID 号 创 建 或 销 毁 对 象 时, 将 有 一 个 静 态 数 据 成 员 记 录 程 序 中 的 对 象 数 执 行 结 果 是 显 示 对 象 ID 及 对 象 数 #include"iostream.h" class Car private: static int counter; // 静 态 数 据 成 员 int obj_id; public: Car(); // 构 造 函 数 static void display_total(); // 静 态 成 员 函 数 void display(); ~Car(); // 析 构 函 数 ; int Car::counter; // 定 义 静 态 数 据 成 员 Car::Car() counter++; obj_id = counter; Car::~Car() counter ; cout<<"object number "<<obj_id<<" being destroyed\n"; void Car::display_total() //static function cout <<"Number of objects created is = "<<counter<<endl;
134 第 7 章 类 与 数 据 抽 象 125 void Car::display() cout << "Object ID is "<<obj_id<<endl; void main() Car a1; Car::display_total(); Car a2, a3; Car::display_total(); a1.display(); a2.display(); a3.display(); 输 出 结 果 : Number of objects created is = 1 Number of objects created is = 3 Object ID is 1 Object ID is 2 Object ID is 3 Object number 3 being destroyed Object number 2 being destroyed Object number 1 being destroyed 在 此 程 序 中, 类 Car 中 有 一 静 态 数 据 成 员 counter, 每 次 创 建 对 象 时 由 构 造 函 数 为 其 加 1, 每 次 销 毁 对 象 时 由 析 构 函 数 减 1 在 main() 函 数 中, 创 建 对 象 a1 后, 通 过 调 用 静 态 成 员 函 数 display_total() 来 显 示 对 象 的 总 数 调 用 静 态 成 员 函 数 所 用 的 方 法, 与 调 用 一 般 成 员 函 数 所 使 用 的 方 法 有 所 不 同 仅 使 用 类 名 称 调 用 函 数 display_total(), 如 下 所 示 : Car::display_total(); 静 态 函 数 display_total() 显 示 已 创 建 的 对 象 数 当 执 行 与 整 个 类 相 关 的 某 个 函 数 时, 不 需 要 引 用 特 定 的 对 象 因 此, 不 使 用 特 定 对 象 的 名 称, 而 是 与 带 有 作 用 域 运 算 符 的 类 本 身 的 名 称 一 起 使 用 静 态 函 数 在 进 一 步 定 义 两 个 类 对 象 a2 和 a3 后, 该 函 数 再 次 被 调 用 成 员 函 数 display() 输 出 每 一 个 对 象 的 对 象 ID 号 在 构 造 函 数 中, 每 次 创 建 对 象 时, 静 态 变 量 counter 的 值 被 赋 给 数 据 成 员 object_id 因 此, 每 一 对 象 具 有 惟 一 编 号 这 显 示 在 输 出 中, 如 下 所 示 : Object ID is 1 Object ID is 2 Object ID is 3 程 序 执 行 完 成 后, 每 一 对 象 均 被 销 毁 销 毁 的 原 则 是 最 后 创 建 的 对 象 最 先 销 毁, 故 具 有 ID3
135 126 C++ 程 序 设 计 的 对 象 首 先 被 销 毁 Object number 3 being destroyed Object number 2 being destroyed Object number 1 being destroyed 本 程 序 中 使 用 的 静 态 成 员 函 数 及 静 态 数 据 成 员 在 需 要 跟 踪 对 象 的 任 何 时 候 都 是 有 用 的, 特 别 是 在 调 试 程 序 时 7.6 友 元 前 面 说 明 了 类 具 有 封 装 和 信 息 隐 藏 的 特 性 只 有 类 的 成 员 函 数 才 能 访 问 类 的 私 有 成 员, 其 他 函 数 无 法 访 问 为 提 高 运 行 效 率, 有 时 确 实 需 要 非 成 员 函 数 能 够 访 问 类 的 私 有 成 员 但 是, 非 成 员 函 数 只 能 访 问 类 的 公 有 成 员, 如 果 将 类 中 的 数 据 成 员 定 义 为 公 有 成 员, 就 破 坏 了 类 的 封 装 性 为 了 解 决 这 个 问 题, 提 出 了 使 用 友 元 的 方 法 友 元 函 数 友 元 函 数 是 一 种 定 义 在 类 外 面 的 普 通 函 数, 它 需 要 在 类 体 内 进 行 说 明 为 区 别 友 元 与 类 成 员 函 数, 在 说 明 友 元 函 数 时 前 面 加 关 键 字 friend 友 元 函 数 不 是 成 员 函 数, 但 是 它 可 以 访 问 类 私 有 成 员 函 数 通 过 一 个 类 中 的 友 元 声 明 成 为 该 类 的 友 元 函 数 例 如 : class person public: void getdata(); friend void display(person p); // 友 元 函 数 的 声 明 ; void display(person p) // 友 元 函 数 没 有 :: 运 算 符 // 一 些 代 码 关 键 字 friend 在 函 数 定 义 中 不 能 重 复, 如 果 同 一 函 数 需 要 访 问 不 同 类 的 对 象, 那 么 最 适 用 的 方 法 是 使 它 成 为 这 些 不 同 类 的 友 元 例 如 : class Teacher; // 前 向 声 明 class Student private: int st_data; public: void getstuddata();
136 第 7 章 类 与 数 据 抽 象 127 friend void display(student s, Teacher t); ; class Teacher private: int th_data; public: void getteachdata(); friend void display(student s, Teacher t); ; void display(student s, Teacher t) // 一 些 代 码 前 向 声 明 是 指 类 在 声 明 之 前 不 能 被 引 用, 需 要 在 前 面 声 明 因 此, 类 Teacher 在 类 Student 之 前 声 明 友 元 函 数 提 高 了 编 程 的 灵 活 性, 但 是 它 们 却 与 面 向 对 象 编 程 的 某 些 原 则 相 悖, 破 坏 了 数 据 的 封 装 和 隐 藏 友 元 函 数 必 须 在 其 要 访 问 的 数 据 所 属 的 类 中 声 明 如 果 类 的 源 代 码 对 于 程 序 员 来 说 不 可 用, 那 么 这 将 无 法 完 成 如 果 类 的 源 代 码 可 用, 那 么 现 有 类 应 尽 可 能 不 做 修 改 友 元 函 数 在 接 口 设 计 选 项 中 提 供 了 一 定 程 度 的 自 由 度 成 员 函 数 和 友 元 函 数 具 有 相 同 的 权 限 成 员 函 数 和 友 元 函 数 不 同 之 处 在 于 友 元 函 数 的 调 用 形 式 类 似 于 func(xobject), 而 成 员 函 数 的 调 用 形 式 则 类 似 于 xobject.func() 例 7.11 友 元 函 数 的 使 用 #include "iostream.h" class Count private: int x; friend void setx(count &, int); public: Count()x=0; void print () cout<<x<<endl; ; void setx(count &c,int val) c.x=val; int main ()
137 128 C++ 程 序 设 计 Count counter; cout<<"counter.x after instantiation:"; counter.print (); cout<<"counter.x after call to setx friend function:"; setx(counter,8); counter.print(); return 0; 运 行 程 序, 输 出 结 果 为 : counter.x after instantiation:0 counter.x after call to setx friend function: 友 元 类 可 以 将 一 个 成 员 函 数 或 几 个 成 员 函 数 或 整 个 类 声 明 为 另 一 个 类 的 友 元 例 7.12 一 个 类 的 成 员 函 数 是 另 一 个 类 的 友 元 class beta; // 前 向 声 明 class alpha private: int a_data; public: alpha() a.data = 10; void display(beta); ; class beta private: int b_data; public: beta() b_data = 20; friend void alpha::display(beta bb); // alpha 类 的 成 员 函 数 为 beta 类 的 友 元 函 数 ; void alpha::display(beta bb) cout<<"\n data of beta ="<<bb.b_data; cout<<"\n data of alpha ="<<a_data; void main()
138 第 7 章 类 与 数 据 抽 象 129 alpha a1; beta b1; a1.display(b1); 当 特 定 类 的 所 有 函 数 或 大 部 分 函 数 必 须 获 得 访 问 另 一 个 类 的 权 限 时, 可 以 考 虑 使 整 个 类 具 有 友 元 权 限 例 7.13 整 个 类 是 另 一 个 类 的 友 元 class beta; class alpha private: int data; public: friend class beta; //beta 是 友 元 类 ; class beta public: void display(alpha d) // 能 够 访 问 alpha cout<<d.data; void get_data(alpha d) // 能 够 访 问 alpha int x = d.data; ; 类 beta 的 所 有 成 员 函 数 都 能 够 访 问 alpha 的 私 有 数 据 成 员 但 是, 类 alpha 的 公 共 成 员 函 数 不 能 访 问 类 beta 的 私 有 成 员 7.7 对 象 的 指 针 和 对 象 的 引 用 对 象 的 指 针 1. 对 象 的 指 针 指 针 可 以 指 向 任 一 类 型 的 变 量, 自 然 也 可 以 指 向 对 象 在 创 建 一 个 类 的 对 象 时, 系 统 会 自 动 在 内 存 中 为 该 对 象 分 配 一 个 确 定 的 存 储 空 间 该 存 储 空 间 在 内 存 中 存 储 的 起 始 地 址 如 果 用 一 个 指 针 来 保 存, 那 么 这 个 指 针 就 是 指 向 对 象 的 指 针, 简 称 对 象 的 指 针
139 130 C++ 程 序 设 计 对 象 的 指 针 的 声 明 方 法 与 普 通 变 量 的 指 针 相 同, 形 式 如 下 : 类 名 * 对 象 的 指 针 名 而 通 过 对 象 的 指 针 间 接 访 问 对 象 成 员 的 方 式 相 应 地 表 示 为 : (* 对 象 的 指 针 名 ). 数 据 成 员 名 ; // 访 问 数 据 成 员 (* 对 象 的 指 针 名 ). 成 员 函 数 名 ( 参 数 表 ); // 访 问 成 员 函 数 注 意 : 因 为 间 接 访 问 运 算 符 * 的 优 先 级 低 于 成 员 选 择 运 算 符., 所 以 表 达 式 中 对 象 的 指 针 名 两 边 的 圆 括 号 不 能 省 略 另 外,C++ 语 言 提 供 了 另 一 个 更 为 常 用 的 方 法 表 述 形 式 如 下 : 对 象 的 指 针 名 > 数 据 成 员 名 ; // 访 问 数 据 成 员 对 象 的 指 针 名 > 成 员 函 数 名 ( 参 数 表 ); // 访 问 成 员 函 数 其 中 的 > 也 叫 做 成 员 选 择 运 算 符, 该 运 算 符 可 用 于 通 过 对 象 的 指 针 或 结 构 变 量 的 指 针 来 访 问 其 中 的 成 员 与 普 通 变 量 的 指 针 相 同, 在 使 用 对 象 的 指 针 之 前 一 定 要 给 指 针 赋 一 个 合 法 的 初 值 下 面 通 过 例 子 来 说 明 对 象 指 针 的 使 用 例 7.14 对 象 指 针 的 使 用 #include "iostream.h" #include "string.h" class Student private: char name[20]; char ID[20]; int age; double score[5]; public: Student (char *str1="",char *str2="",int a=0,double s0=0,double s1=0,double s2=0,double s3=0,double s4=0) strcpy(name,str1); strcpy(id,str2); age=a; score[0]=s0; score[1]=s1; score[2]=s2; score[3]=s3; score[4]=s4; void display(); ;
140 第 7 章 类 与 数 据 抽 象 131 void Student::display() cout<<"name: "<<name<<endl; cout<<"id: "<<ID<<endl; cout<<"age: "<<age<<endl; for(int i=0;i<5;i++) cout<<"score "<<i<<" : "<<score[i]<<endl; void main() Student p1("zhangsan"," ",19,98,79,78,87,99); Student *pt=&p1; // 定 义 指 向 对 象 的 指 针 pt Pt >display(); 程 序 执 行 结 果 为 : Name: zhangsan ID: Age: 19 Score 0 : 98 Score 1 : 79 Score 2 : 78 Score 3 : 87 Score 4 : 对 象 的 指 针 作 为 函 数 的 参 数 使 用 对 象 指 针 作 为 函 数 的 参 数 要 比 对 象 作 为 函 数 的 参 数 使 用 的 要 多 使 用 对 象 指 针 作 为 函 数 的 参 数 可 以 实 现 参 数 值 的 双 向 传 递, 另 外, 不 必 为 形 参 分 配 空 间, 进 行 对 象 值 的 复 制 这 样, 提 高 了 程 序 的 运 行 的 效 率 例 7.15 分 析 下 面 程 序 执 行 结 果 #include "iostream.h" #include "string.h" class person private: char name[20]; char ID[20]; int age; double account; public: person(char *str1="",char *str2="",int a=0,double ac=0 )
141 132 C++ 程 序 设 计 strcpy(name,str1); strcpy(id,str2); age=a; account=ac; double GetAccount()return account; void display(); ; void person::display() cout<<"name: "<<name<<endl; cout<<"id: "<<ID<<endl; cout<<"age: "<<age<<endl; cout<<"account : "<<account<<endl; double fun(person *p) // 对 象 的 指 针 作 为 函 数 的 参 数 double x; x=p >GetAccount()*0.15; return x; void main() person p1(" 张 三 "," ",22, ); person *pt=&p1; pt >display(); cout<<"personal tax is :"<<fun(pt)<<endl; 程 序 运 行 结 果 为 : Name: 张 三 ID: Age: 22 Account : 1e+006 Personal tax is : this 指 针 this 指 针 也 是 一 个 指 向 对 象 的 指 针, 不 过 比 较 特 殊 它 隐 含 在 类 的 成 员 函 数 中, 用 来 指 向 成 员 函 数 所 属 类 的 正 在 被 操 作 的 对 象
142 第 7 章 类 与 数 据 抽 象 133 实 际 上, 当 一 个 对 象 的 成 员 函 数 被 调 用 时, 系 统 会 自 动 向 它 传 递 一 个 隐 含 的 参 数, 该 参 数 就 是 一 个 指 向 正 被 该 函 数 操 作 的 对 象 的 指 针, 在 程 序 中 使 用 关 键 字 this 来 引 用 该 指 针 编 译 系 统 会 首 先 将 这 个 对 象 的 地 址 赋 给 被 调 用 的 成 员 函 数 中 的 this 指 针, 然 后 再 调 用 成 员 函 数 而 成 员 函 数 访 问 数 据 成 员 时 就 隐 含 地 使 用 this 指 针 来 确 保 要 访 问 的 数 据 成 员 属 于 这 个 对 象 this 指 针 是 C++ 实 现 封 装 的 一 种 机 制, 它 将 数 据 成 员 和 成 员 函 数 连 接 在 一 起, 当 一 个 成 员 函 数 对 数 据 成 员 进 行 操 作 时, 用 this 指 针 来 表 示 数 据 成 员 所 在 的 对 象 当 程 序 操 作 不 同 对 象 的 成 员 函 数 时,this 指 针 也 指 向 不 同 的 对 象 例 如 : cout<<m<<endl; cout<<this >m<<endl; 上 面 的 两 个 语 句 作 用 是 相 同 的, 都 输 出 显 示 变 量 m 的 值, 只 是 第 一 句 隐 含 地 使 用 了 this 指 针, 第 二 句 显 示 地 使 用 了 this 指 针 注 意 : 静 态 成 员 函 数 没 有 this 指 针 例 7.16 this 指 针 的 使 用 #include "iostream.h" class Person private: int num; int age; public: void display(); ; void Person :: display() this >num=1001; // 与 num=1001 相 同 this >age = 20; // 与 age=20 相 同 cout<<this >num<<" "<<this >age<<endl; // 与 cout<<num<<" "<<age<<endl; 相 同 void main() Person Lili; Lili.display(); 程 序 运 行 结 果 为 : this 指 针 的 有 用 之 处 在 于 它 能 从 成 员 函 数 中 返 回 值 对 象 引 用 在 实 际 编 程 中, 使 用 对 象 的 引 用 作 为 函 数 的 参 数 要 比 使 用 对 象 指 针 作 为 函 数 的 参 数 更 多 一
143 134 C++ 程 序 设 计 些 使 用 对 象 的 引 用 作 为 函 数 的 参 数 不 仅 具 有 对 象 指 针 作 为 函 数 的 参 数 的 优 点, 更 能 说 明 对 象 的 引 用 的 直 观 与 简 洁 例 7.17 对 象 的 引 用 作 为 函 数 的 参 数, 分 析 程 序 执 行 情 况 #include "iostream.h" #include "string.h" class P private: char num[20]; int grade; public: P(char *str="",int g=20)strcpy(num,str); grade = g; void set(int gg=0)grade=gg; void display(); ; void P :: display() cout<< num<<" "<< grade<<endl; void fun(p &p1) // 对 象 的 引 用 作 为 函 数 的 参 数 p1.set(9); void main() P p1("weifeng",12); fun(p1); p1.display(); 程 序 运 行 结 果 为 : WeiFeng 9 该 程 序 使 用 对 象 的 引 用 作 为 函 数 的 参 数 实 参 和 形 参 指 的 是 同 一 个 对 象, 不 必 再 对 形 参 分 配 空 间, 在 调 用 程 序 过 程 中 对 形 参 的 改 变 将 影 响 实 参 的 值 另 外, 实 参 的 形 式 也 很 简 单 7.8 对 象 数 组 对 象 数 组 是 指 数 组 元 素 为 对 象 的 数 组 对 象 数 组 的 定 义 使 用 与 一 般 数 组 相 同, 只 不 过 数 组 元 素 不 同 而 已 对 象 数 组 定 义 的 一 般 格 式 为 :
144 第 7 章 类 与 数 据 抽 象 135 < 类 名 > < 对 象 数 组 名 >[< 长 度 >] 其 中,< 类 名 > 是 要 定 义 对 象 数 组 元 素 所 属 类 的 名 字, 即 所 定 义 的 对 象 数 组 元 素 是 该 类 类 型 的 对 象 ;[< 长 度 >] 指 的 是 数 组 元 素 的 个 数, 有 一 个 方 括 号 是 一 维, 有 两 个 方 括 号 是 二 维, 多 个 方 括 号 是 多 维 例 如 : person p[10]; person pp[2][3]; p 是 一 维 对 象 数 组 名, 有 10 个 person 对 象 ;pp 是 二 维 对 象 数 组 名, 有 6 个 person 对 象 定 义 对 象 数 组 的 类, 要 有 无 参 的 构 造 函 数, 或 构 造 函 数 的 参 数 有 默 任 值 当 定 义 一 个 对 象 数 组 时, 系 统 为 对 象 数 组 的 每 一 个 数 组 元 素 调 用 一 次 构 造 函 数, 来 初 始 化 每 一 个 数 组 元 素 例 7.18 分 析 下 面 程 序 执 行 结 果 #include "iostream.h" class A private: int x; public: A(int xx=100)x=xx; cout<< "Constructor called.\n"; ~A()cout<<"Destructor called. "<<x<<endl; void set(int xx=100)x=xx; void display(); ; void A:: display() cout<<x<<endl; void main() A a[3]; for(int i=0;i<3;i++) a[i].set(100+i*100); for(int j=0;j<3;j++) a[j].display(); 程 序 运 行 结 果 为 : Constructor called. Constructor called. Constructor called
145 136 C++ 程 序 设 计 300 Destructor called. 300 Destructor called. 200 Destructor called. 100 对 象 数 组 可 以 被 初 始 化 不 同 的 值, 也 可 以 赋 值 例 7.19 分 析 下 面 程 序 执 行 结 果 #include "iostream.h" class A private: int x; public: A(int xx=100)x=xx; cout<<x<<" Constructor called.\n"; ~A()cout<<x<<" Destructor called."<<endl; void set(int xx=100)x=xx; void display(); ; void A:: display() cout<<x<<endl; void main() A a[3]=a(10),a(20),a(30); for(int j=0;j<3;j++) a[j].display(); 程 序 运 行 结 果 : 10 Constructor called. 20 Constructor called. 30 Constructor called Destructor called. 20 Destructor called. 10 Destructor called. 上 面 对 象 元 素 的 初 始 化 也 可 以 用 下 面 的 赋 值 方 式 得 到 初 值 : a[0]=a(10);
146 a[1]=a(20); a[2]=a(30); 但 程 序 的 执 行 结 果 不 同, 请 读 者 自 行 考 虑 常 指 针 和 常 引 用 第 7 章 类 与 数 据 抽 象 常 类 型 1. 常 量 和 常 指 针 常 量 是 一 个 在 程 序 执 行 过 程 中 值 不 能 改 变 的 量 C++ 中 的 关 键 字 const 可 以 加 到 对 象 的 声 明 中 使 该 对 象 成 为 一 个 常 量 而 不 是 变 量 常 量 不 能 改 变, 因 此 必 须 对 常 量 进 行 初 始 化 例 如 : const int Maxsize=100; Maxsize =200; // 错 误, 不 允 许 改 变 常 量 ++ Maxsize; // 错 误, 不 允 许 改 变 常 量 const 也 可 以 修 饰 指 针 变 量, 当 使 用 带 有 指 针 的 const 时, 有 两 种 含 义 : 一 是 指 针 本 身 是 一 个 变 量, 二 是 指 针 指 向 的 内 容 是 一 个 变 量 当 把 const 置 于 指 针 声 明 之 前 时, 可 以 使 指 针 指 向 的 内 容 是 一 个 变 量, 而 不 是 使 指 针 变 成 一 个 常 量 例 如 : int i =10; const int *iptr = &i; *iptr = 10; // 错 误, 指 针 指 向 的 内 容 是 一 个 变 量 i = 20; // 正 确,i 不 是 常 量 int x = 30; iptr = &x; //iptr 不 是 常 量, 可 以 指 向 其 他 变 量 *iptr = 50; // 错 误, 指 针 指 向 的 内 容 是 一 个 变 量 将 const 置 于 指 针 声 明 之 后, 是 将 指 针 本 身 声 明 为 常 量, 而 不 是 指 针 指 向 的 内 容 例 如 : double d1 = 99.9; double *const dptr = &d1; // 常 量 指 针 指 向 double 型 变 量 *dptr = ; // 正 确 double d2 = 45.67; dptr = &d2; // 错 误,dptr 是 一 个 常 量 const 关 键 字 还 可 在 参 数 列 表 中 使 用, 使 得 在 函 数 中 不 允 许 对 参 数 进 行 修 改 此 特 性 在 函 数 参 数 中 特 别 有 用 例 如 : void Myfunc(const char *str) str="hello world! "; // 有 效 *str = 'A'; // 错 误 又 如 : void Myfunc1(const int index)
147 138 C++ 程 序 设 计 iindex = 100; // 错 误 2. 常 引 用 使 用 const 修 饰 符 说 明 引 用 时, 则 该 引 用 为 常 引 用 该 引 用 所 引 用 的 对 象 不 能 被 更 改 常 引 用 的 定 义 格 式 为 : const < 类 型 说 明 > &< 引 用 名 >; 例 如 : int y=100; const int & x=y; y=200; // 正 确 x=300; // 错 误, 常 引 用 不 能 被 更 改 常 成 员 函 数 使 用 const 说 明 的 成 员 函 数, 称 为 常 成 员 函 数 只 有 常 成 员 函 数 才 有 权 使 用 常 量 或 常 对 象, 没 有 使 用 const 说 明 的 成 员 函 数 不 能 使 用 常 对 象 常 成 员 函 数 说 明 的 格 式 为 : < 类 型 说 明 > < 函 数 名 > (< 参 数 表 >) const; 在 函 数 后 面 的 说 明 的 const 是 函 数 的 一 个 组 成 部 分, 因 此, 在 函 数 的 定 义 部 分 也 必 须 加 上 const 关 键 字 例 7.20 分 析 下 面 程 序 执 行 结 果 #include "iostream.h" class Point private: int x,y; public: Point(int xx=0,int yy=0)x=xx; y=yy; void display()const; void display(); ; void Point::display() cout<<x<<" ***** "<<y<<endl; void Point::display()const cout<<x<<" const "<<y<<endl;
148 第 7 章 类 与 数 据 抽 象 139 void main() Point p(100,89); p.display(); const Point pc(200,98); pc.display(); 程 序 运 行 结 果 为 : 100 ***** const 98 在 Point 类 中, 有 两 个 同 名 的 成 员 函 数, 但 是 它 们 的 类 型 不 同, 一 个 是 void, 另 一 个 是 void 加 const, 这 是 两 个 重 载 的 成 员 函 数 常 数 据 成 员 关 键 字 const 不 仅 可 以 修 饰 成 员 函 数, 也 可 以 修 饰 数 据 成 员 由 于 const 修 饰 的 对 象 不 能 更 改, 所 以 必 须 进 行 初 始 化 因 此, 在 类 中 定 义 const 数 据 成 员 时, 要 通 过 成 员 初 始 化 列 表 的 方 式 来 生 成 构 造 函 数 对 数 据 成 员 初 始 化 例 7.21 常 数 据 成 员 的 使 用 #include "iostream.h" class Circle private: int x,y; const double PI; double r; public: Circle(int xx=0,int yy=0,double rr=0):pi( )x=xx; y=yy;r=rr; double area()return PI*r*r; void display(); ; void Circle::display() cout<<" 圆 心 位 置 : ("<<x<<","<<y<<")"<<endl; cout<<" 半 径 大 小 为 : "<<r<<endl; cout<<" 圆 的 面 积 为 : "<<area()<<endl; void main() Circle c(100,200,10);
149 140 C++ 程 序 设 计 c.display(); 程 序 运 行 结 果 为 : 圆 心 位 置 : (100,200) 半 径 大 小 为 : 10 圆 的 面 积 为 : 习 题 1. 在 C++ 中, 对 象 定 义 的 格 式 是 怎 样 的? 2. 如 果 某 类 定 义 了 5 个 对 象, 那 么 会 在 内 存 中 存 储 多 少 个 该 类 的 数 据 项 的 副 本? 多 少 个 其 成 员 函 数 的 幅 本? 3. 解 释 类 和 对 象 有 什 么 区 别 4. 公 有 成 员 和 私 有 成 员 有 什 么 区 别? 5. 说 明 友 元 关 系 的 概 念, 说 明 友 元 关 系 的 副 作 用 6. 什 么 是 构 造 函 数 和 析 构 函 数? 各 有 哪 些 特 点? 7. 什 么 是 复 制 构 造 函 数? 它 有 何 作 用? 8. 已 知 圆 的 半 径, 编 写 程 序 计 算 其 周 长 和 面 积, 用 类 来 实 现 9. 编 写 程 序 创 建 Number 类, 它 有 两 个 整 型 数 据 成 员 x 和 y 它 应 包 含 成 员 函 数 以 读 取 数 据, 对 两 个 数 据 进 行 加 减 乘 除 运 算, 并 显 示 结 果 10. 编 写 程 序, 处 理 学 生 成 绩 单 可 以 从 键 盘 读 取 下 列 各 项 : Name of student( 学 生 姓 名 ) Roll number( 学 号 ) Subject_ID( 学 科 编 号 ) Subject Marks( 学 科 成 绩 ) 假 定 考 试 涉 及 5 个 学 科 在 程 序 中 应 显 示 考 试 分 数 还 应 该 包 括 成 员 函 数, 用 于 计 算 和 显 示 5 个 学 科 的 总 分 及 平 均 分 可 以 使 用 下 面 的 类 结 构 : class Student private: char name[30]; int rollno; int sub_id[5]; int sub_marks[5]; public: void getinfo(); int total(); void display(); int averate();
150 第 7 章 类 与 数 据 抽 象 141 ; 11. 分 析 下 列 程 序 的 输 出 结 果 #include "iostream.h" class MyCla private: int x,y; public: MyCla(); MyCla(int xx); MyCla(int xx,int yy); MyCla(MyCla &); void Display(); void Set(int, int); ~ MyCla(); ; MyCla:: MyCla() cout<<" 执 行 无 参 构 造 函 数 :" ; x=0;y=0; cout<<"x="<<x<<"y="<<y<<endl; MyCla:: MyCla(int xx) cout<<" 执 行 一 个 参 数 构 造 函 数 :" ; x=xx;y=0; cout<<"x="<<x<<"y="<<y<<endl; MyCla:: MyCla(int xx,int yy) cout<<" 执 行 两 个 参 数 构 造 函 数 :" ; x=xx;y=yy; cout<<"x="<<x<<"y="<<y<<endl; MyCla:: MyCla(MyCla &a) cout<<" 执 行 复 制 构 造 函 数 :" ; x=a.x;y=a.y; cout<<"x="<<x<<"y="<<y<<endl;
151 142 C++ 程 序 设 计 void MyCla:: Display() cout<<" 执 行 显 示 函 数 :" ; cout<<"x="<<x<<"y="<<y<<endl; void MyCla:: Set(int xx=0,int yy=0) cout<<" 执 行 设 置 函 数 :" ; x=xx;y=yy; cout<<"x="<<x<<"y="<<y<<endl; MyCla:: MyCla () cout<<" 执 行 析 构 函 数 :" ; cout<<"x="<<x<<"y="<<y<<endl; (1) 主 程 序 为 : void main() MyCla a; MyCla b(101); MyCla c(87,98); (2) 主 程 序 为 : void main() MyCla a(57,28); a.set(); a.set(86); a.display(); a.set(24,75); a.display(); (3) 主 程 序 为 : void main() MyCla a(33); a.set(86,543);
152 第 7 章 类 与 数 据 抽 象 143 a.display(); MyCla b(a); b.display(); (4) 主 程 序 为 : void main() MyCla a(33); MyCla b(223,54); MyCla c(38,84); b.display(); a.display(); 12. 在 C++ 中, 对 象 作 为 函 数 参 数 与 对 象 指 针 作 为 函 数 参 数 有 何 不 同? 13. 什 么 是 this 指 针? 14. 使 用 const 修 饰 指 针 时,const 出 现 的 位 置 对 功 能 有 何 影 响? 15. 运 算 符 new 和 delete 的 功 能 是 什 么? 16. 设 计 一 个 表 示 矩 形 的 类 Rectangle, 其 数 据 成 员 为 double *Length 和 double *Width, 设 计 各 种 操 作, 并 且 应 用 指 针 建 立 对 象 测 试 类 17. 对 象 指 针 作 函 数 参 数 和 对 象 引 用 作 函 数 参 数 有 何 区 别? 18. 对 象 数 组 是 怎 样 进 行 声 明 的? 怎 样 建 立 对 象 数 组 和 标 志 对 象 数 组 的 元 素? 19. 编 写 程 序, 从 键 盘 读 入 学 生 的 出 生 日 期, 读 取 格 式 为 : 日 月 年, 并 按 此 格 式 输 出 例 如, 输 入 为 , 则 输 出 为 : 12 October 1998 要 求 按 类 形 式 完 成 20. 常 量 有 几 种 类 型? 如 何 定 义 它 们? 21. 编 写 程 序, 从 键 盘 读 入 整 数, 计 算 出 各 位 数 字 之 和, 直 到 为 一 位 数 字 例 如, 输 入 数 据 是 2896, 则 sum= =25 sum=2+5=7 可 以 使 用 下 面 具 有 一 个 整 型 数 据 成 员 和 成 员 函 数 的 类 结 构 来 接 收 用 户 输 入 的 数 据, 进 行 和 计 算, 然 后 显 示 结 果 class Number private: int num; public: void getdata(); int adddigits();
153 144 C++ 程 序 设 计 void display(); ; 结 果 显 示 为 下 面 格 式 : The sum of digits of 2896 is 下 列 程 序 段 建 立 了 指 针 对 象 P 与 对 象 数 组 A 的 链 接 关 系 : int a[5], i ; int *P=&a[0]; 解 释 下 列 语 句 的 语 义 : (1)i=*p++; (2)i=*++p; (3)P=P+2; (4)P=a+4; 23. 写 出 下 列 程 序 的 执 行 结 果 : #include"iostream.h" class A int a; double b; public: A(int x=100,double y=1.2)a=x;b=y; void show(char *pt) cout<<pt<<":"<<endl; cout<<"a="<<a<<endl; cout<<"b="<<b<<endl; ; void main() A obj1,obj2(100,3.5); obj1.show("obj1"); obj2.show("obj2"); A *p; p=&obj1; p >show("p >obj1"); (*p).show("(*p)obj1"); p=&obj2; p >show("p >obj2"); (*p).show("(*p)obj2");
154 p=new A; p >show("p >new"); delete p; 24. 说 明 下 面 的 程 序 中 this 和 *this 的 用 法 #include"iostream.h" class B public: B() a=b=0; B(int i,int j)a=i;b=j; void copy(b &aa); void print() cout<<a<<","<<b<<endl; private: int a,b; ; void B::copy(B &aa) if(this==&aa) return ; *this=aa; void main() B a1,a2(30,40); a1.copy(a2); a1.print(); 25. 分 析 下 列 程 序, 指 出 该 程 序 中 定 义 了 几 种 常 类 型 量 #include"iostream.h" class C public: C(int i) p=i; 第 7 章 类 与 数 据 抽 象 145
155 146 C++ 程 序 设 计 int getp() return p; const int fun(int i)const return p+i; private: int p; ; void main() C a(4); const int b=a.fun(6); int c=a.getp(); cout<<b<<','<<c<<endl; const C d(20); cout<<d.fun(3)<<endl; cout<<d.getp()<<endl;
156 第 8 章 运 算 符 重 载 C++ 中 的 运 算 符 重 载 就 是 给 已 有 运 算 符 赋 予 更 多 的 含 义 通 过 重 新 定 义 运 算 符, 使 它 能 够 用 于 特 定 类 的 对 象 执 行 特 定 的 功 能 运 算 符 重 载 提 供 了 重 新 定 义 语 言 扩 展 语 言 的 能 力, 使 程 序 更 加 容 易 阅 读 和 调 试 运 算 符 重 载 可 以 通 过 成 员 函 数 或 友 元 函 数 来 实 现, 注 意 两 者 之 间 的 不 同 之 处 8.1 概 述 运 算 符 通 常 是 针 对 类 中 的 私 有 成 员 进 行 操 作, 因 此 重 载 运 算 符 应 该 能 够 访 问 类 中 的 私 有 成 员, 所 以 运 算 符 重 载 一 般 采 用 成 员 函 数 或 友 元 函 数 的 方 式 运 算 符 重 载 的 过 程 是 将 现 有 运 算 符 与 成 员 函 数 或 友 元 函 数 相 关 联, 使 得 该 运 算 符 具 有 将 该 类 的 对 象 用 作 其 操 作 数 的 能 力 如 +,,>, += 及 == 等 运 算 符, 只 能 用 在 如 int 和 double 等 基 本 数 据 类 型 的 操 作 之 上, 而 不 能 应 用 于 用 户 定 义 的 数 据 类 型 的 实 例 上 通 过 运 算 符 重 载, 允 许 使 用 在 像 下 面 这 样 的 语 句 中, 例 如 : if (obj1<=obj2) 其 中 obj1 和 obj2 为 类 的 对 象, 对 象 的 比 较 运 算 可 在 成 员 函 数 中 定 义 或 在 友 元 中 定 义, 并 与 比 较 运 算 符 关 联 编 译 器 可 以 通 过 检 查 运 算 符 数 据 类 型 来 区 分 重 载 的 运 算 符 运 算 符 重 载 是 多 态 性 的 一 种 形 式, 即 运 算 符 多 态 性 运 算 符 重 载 可 以 使 程 序 更 加 容 易 阅 读 和 调 试 如 果 以 下 语 句 出 现, 很 容 易 理 解 是 两 个 对 象 在 相 加, 并 将 结 果 赋 予 第 三 个 对 象 例 如 : obj3 = obj1 + obj2; 而 不 是 obj3.add (obj1,obj2); 的 形 式 8.2 运 算 符 重 载 的 一 般 规 则 运 算 符 重 载 具 有 以 下 原 则 (1) 重 载 的 运 算 符 是 C++ 中 已 经 存 在 的 运 算 符, 不 能 够 主 观 创 造 (2) 运 算 符 重 载 不 能 改 变 运 算 符 的 语 法 结 构, 即 操 作 数 的 个 数 例 如, 增 量 运 算 符 ++ 和 减 量 运 算 符 只 能 重 载 为 一 元 运 算 符 使 用, 不 能 重 载 为 二 元 运 算 符 使 用 (3) 运 算 符 重 载 不 能 改 变 C++ 语 言 中 已 定 义 的 运 算 符 的 优 先 顺 序 和 结 合 性
157 148 C++ 程 序 设 计 (4) 运 算 符 重 载 一 般 不 改 变 运 算 符 功 能 例 如, 重 载 的 + 运 算 符 可 以 用 来 计 算 两 个 对 象 的 乘 积, 但 会 使 你 的 代 码 不 可 读 (5) 不 能 重 载 的 运 算 符 有 :sizeof() 运 算 符 成 员 运 算 符 (.) 指 向 成 员 的 指 针 运 算 符 (*) 作 用 域 运 算 符 (::) 以 及 条 件 运 算 符 (?:) 8.3 一 些 特 殊 操 作 符 的 重 载 运 算 符 重 载 函 数 是 指 含 有 实 际 的 重 载 运 算 符 的 函 数, 一 般 采 用 两 种 形 式 : 重 载 为 类 的 成 员 函 数 形 式 和 友 元 函 数 形 式 一 元 运 算 符 重 载 1. 重 载 为 类 的 成 员 函 数 将 运 算 符 重 载 函 数 说 明 为 类 的 成 员 函 数 的 格 式 如 下 : < 类 型 > operator < 运 算 符 > (< 参 数 列 表 >) 要 重 载 的 运 算 符 必 须 置 于 关 键 字 operator 之 后 一 元 运 算 符 只 有 一 个 操 作 数, 例 如 增 量 运 算 符 ++ 减 量 运 算 符 和 一 元 负 运 算 符 ( ) 增 量 运 算 符 和 减 量 运 算 符 可 以 用 于 前 缀 或 后 缀 运 算 例 8.1 重 载 运 算 符 ++ class Point private: int xcoord; int ycoord; public: Point ()xcoord =0; ycoord =0; void operator++() ++xcoord; ++ ycoord; ; void main() Point obj1; obj1++; // 使 xcoord ycoord 增 加 1 ++obj1; // 使 xcoord ycoord 增 加 2 如 果 在 类 的 说 明 符 中 发 现 存 在 重 载 运 算 符 函 数, 则 该 语 句 增 加 对 象 obj1++, 通 过 编 译 器 解 释 为 : obj1.operator++(); 用 于 减 少 对 象 的 类 似 函 数 也 可 在 类 中 出 现 : void operator ()
158 第 8 章 运 算 符 重 载 149 xcoord; ycoord; 可 以 通 过 语 句 obj1; 或 obj ; 调 用 重 载 的 减 量 运 算 符 函 数 对 于 重 载 的 增 量 和 减 量 运 算 符, 首 先 会 执 行 运 算 符 函 数 无 论 该 运 算 符 是 前 缀 还 是 后 缀, 对 obj1++ 或 ++obj1 都 没 有 影 响 但 是 当 执 行 obj1 = obj2++ 时 会 出 现 问 题, 必 须 修 改 该 函 数 以 使 它 能 够 返 回 一 个 增 量 的 对 象 Point Point::operator++() Point p; // 创 建 一 个 临 时 对 象 p. xcoord =++xcoord; // 增 量 赋 值 p. ycoord = ++ycoord; return p; // 返 回 增 量 后 的 对 象 另 一 种 方 法 是 创 建 一 个 匿 名 临 时 对 象, 并 将 它 返 回, 例 如 : class Point private: int xcoord; int ycoord; public: Point () // 无 参 数 构 造 函 数 xcoord = 0; ycoord=0; Point (int x,int y) // 带 参 数 构 造 函 数 xcoord =x; ycoord =y; Point operator++(); // 运 算 符 重 载 为 类 的 成 员 函 数 ; Point Point::operator++() ++ xcoord; ++ycoord; return Point(xcoord,ycoord); // 或 只 返 回 Point(++xcoord,++ ycoord ); 在 返 回 语 句 中, 带 参 数 的 构 造 函 数 创 建 了 类 Point 的 一 个 匿 名 的 临 时 对 象
159 150 C++ 程 序 设 计 从 成 员 函 数 返 回 对 象 的 另 一 种 方 法 是 使 用 this 指 针 例 如 : Point Point::operator++() ++ xcoord; ++ycoord; return(*this); 这 种 方 法 不 需 要 带 有 参 数 的 构 造 函 数 从 上 面 的 例 子 中 看 出, 重 载 ++ 和 后, 前 缀 和 后 缀 运 算 符 之 间 不 再 有 区 别 表 达 式 obj2 = obj1++; 和 obj2 = ++obj1; 会 得 出 同 样 的 效 果 为 了 实 现 后 缀 运 算 重 载 运 算 符 ++, 必 须 定 义 一 个 带 有 单 参 数 的 函 数 例 如 : Point Point::operator++(int) return Point (xcoord ++, ycoord++); 2. 重 载 为 类 的 友 元 函 数 一 元 运 算 符 重 载 为 类 的 成 员 函 数 时, 不 用 再 显 示 说 明 参 数 因 为 重 载 为 类 的 成 员 函 数, 总 是 隐 藏 了 一 个 参 数, 该 参 数 是 this 指 针 this 指 针 是 指 向 调 用 该 成 员 函 数 对 象 的 指 针 当 重 载 为 类 的 友 元 函 数 时, 由 于 不 存 在 隐 含 的 this 指 针, 对 一 元 运 算 符 来 说, 友 元 函 数 有 一 个 参 数 将 运 算 符 重 载 函 数 说 明 为 类 的 友 元 函 数 的 格 式 如 下 : < 类 型 > operator < 运 算 符 >(< 参 数 列 表 >) 必 须 在 类 的 定 义 中 说 明 该 运 算 符 重 载 函 数 为 类 的 友 元 函 数 例 8.2 用 友 元 函 数 重 载 运 算 符 ++ #include "iostream.h" class Point private: int xcoord; int ycoord; public: Point() // 无 参 数 构 造 函 数 xcoord = 0; ycoord=0; Point(int x,int y) // 带 参 数 构 造 函 数
160 第 8 章 运 算 符 重 载 151 xcoord = x; ycoord =y; void display()cout<< " ("<< xcoord <<","<<ycoord<<")"<<endl; friend Point operator++(point &); // 前 缀 自 增 friend Point operator++(point &,int); // 后 缀 自 增 ; Point operator++( Point &e) return Point (++e. xcoord, ++e. ycoord); Point operator++( Point &e,int) return Point (e. xcoord ++, e. ycoord ++); void main() Point p1(10,10),p2; p2=p1++; p1.display(); p2.display(); p2=++p1; p1.display(); p2.display(); 程 序 运 行 结 果 为 : (11,11) (10,10) (12,12) (12,12) 两 种 重 载 运 算 符 的 比 较 : 一 般 情 况 下, 单 目 运 算 符 常 使 用 成 员 函 数 重 载 运 算 符, 而 双 目 运 算 符 常 使 用 友 元 函 数 进 行 运 算 符 重 载 如 果 编 程 人 员 没 有 为 类 重 载 运 算 符 = 和 &, 则 编 译 器 将 为 类 生 成 缺 省 的 = 和 & 运 算, 其 他 运 算 符 则 必 须 由 程 序 员 自 己 定 义 当 需 要 重 载 运 算 符 具 有 可 交 换 性 时, 选 择 重 载 为 友 元 函 数 更 为 适 宜 二 元 运 算 符 重 载 1. 二 元 算 术 运 算 符 重 载 二 元 运 算 符 重 载 为 类 的 成 员 函 数, 它 们 包 含 一 个 形 参, 即 运 算 符 右 侧 的 值 例 如, 当 要 完 成 obj1+obj2 时, 重 载 运 算 符 + 为 成 员 函 数 的 声 明 如 下 :
161 152 C++ 程 序 设 计 Example operator+(example obj2) 作 为 友 元 函 数, 它 们 含 有 两 个 参 数 例 如 : Example operator+(example obj1,example obj2) 需 要 两 个 操 作 数 进 行 运 算 例 8.3 加 法 运 算 符 重 载 Point Point::operator+(Point a) Point p; // 临 时 对 象 p.xcoord= xcoord+ a. xcoord ; p.ycoord= ycoord+ a. ycoord ; return p; // 返 回 临 时 对 象 现 在 可 以 使 用 以 下 语 句 将 对 象 进 行 加 操 作 : obj3 = obj1 + obj2; // 类 Example 对 象 运 算 符 + 可 以 访 问 两 个 对 象 : 运 算 符 左 侧 对 象 obj1 是 将 要 调 用 函 数 的 对 象, 右 侧 对 象 obj2 作 为 函 数 调 用 的 参 数 因 为 它 是 调 用 函 数 的 对 象, 所 以 可 直 接 访 问 左 侧 操 作 数 ( 即 对 象 obj1), 把 右 侧 操 作 数 a.count 作 为 参 数 来 访 问 还 可 以 进 行 : obj4 = obj3 + obj2 + obj1; 能 够 进 行 这 种 多 项 加 操 作, 是 因 为 在 + 运 算 符 函 数 的 返 回 类 型 为 Sample 类 型 的 对 象 例 8.4 为 字 符 串 重 载 + 运 算 符 String String::operator+(String ss) String temp; // 声 明 一 个 临 时 字 符 串 temp strcpy(temp.str,str); // 将 该 字 符 串 复 制 到 temp strcat(temp.str,ss.str); // 参 数 字 符 串 相 加 return temp; // 返 回 temp 字 符 串 按 以 下 方 式 使 用 : String s1 = "Welcome"; String s2 = "to C++"; String s3; s3 = s1 + s2; 例 8.5 重 载 复 合 赋 值 运 算 符 void Point::operator+=(Point a) xcoord += a.xcoord; ycoord += a.ycoord; 不 需 要 临 时 对 象 对 象 是 调 用 函 数 的 对 象, 其 数 据 成 员 已 经 改 变 由 于 赋 值 运 算 符 的 结 果 没 有
162 第 8 章 运 算 符 重 载 153 赋 给 任 何 变 量, 函 数 同 样 不 需 要 返 回 值, 该 运 算 符 用 于 下 面 这 样 的 表 达 式 : obj1 += obj2; 函 数 需 要 有 一 个 返 回 值, 以 便 在 更 复 杂 的 表 达 式 中 使 用 例 如 : obj3 = obj1 += obj2; 成 员 函 数 的 声 明 为 : Point Point::operator+=(Pointe a); 返 回 语 句 可 以 写 为 : return Point(xcoord,ycoord); 其 中, 一 个 匿 名 对 象 被 初 始 化 为 与 该 对 象 相 同 的 值 2. 重 载 比 较 和 逻 辑 运 算 符 比 较 和 逻 辑 运 算 符 是 二 元 运 算 符, 二 元 运 算 符 需 要 两 个 对 象 才 能 进 行 比 较 可 重 载 的 比 较 运 算 符 包 括 <,<=,>,>=,== 和!= 可 重 载 的 逻 辑 运 算 符 包 括 && 和 例 如 : int String::operator>(String ss) return(strcmp(str,ss.str)); 3. 重 载 赋 值 运 算 符 默 认 赋 值 运 算 符 仅 将 源 对 象 逐 字 节 复 制 到 目 的 对 象, 如 果 数 据 成 员 包 含 指 针 且 已 经 使 用 运 算 符 new 分 配 内 存 例 8.6 分 析 下 面 程 序 执 行 情 况 class String private: char *str; public: String(char *s = "") int length = strlen(s); str = new char[length+1]; strcpy(str,s); ~String() // 析 构 函 数 delete[] str; void display() cout<<str;
163 154 C++ 程 序 设 计 ; void main() String s1("welcome to C++ world \n"); String s2; s2 = s1; s1.display(); s2.display(); 主 函 数 main() 创 建 了 两 个 对 象 s1 和 s2 构 造 函 数 为 字 符 串 分 配 内 存, 并 将 形 参 复 制 到 其 中 进 行 输 出 : Welcome to C++ world Welcome to C++ world Null pointer assignment 赋 值 后, 两 个 对 象 s1 和 s2 的 数 据 成 员 str 指 向 同 一 内 存 地 址 当 对 象 s1 和 s2 销 毁 时, 指 向 同 一 内 存 地 址 空 间 被 释 放 两 次, 造 成 错 误 出 现 对 两 个 对 象 的 指 针 指 向 同 一 内 存 地 址 的 问 题 的 解 决 方 法 为 : String& String::operator=(String& s) delete str; int length = strlen(s.str); str = new char[length+1]; strcpy(str,s.str); return(*this); 在 程 序 中 加 入 该 函 数 后 就 不 会 出 现 错 误 消 息 当 重 载 赋 值 运 算 符 时, 必 须 确 保 将 一 个 对 象 中 所 有 的 数 据 成 员 全 部 复 制 到 另 一 个 运 算 符 函 数 中 如 果 包 括 更 多 的 数 据 成 员, 则 每 个 成 员 都 需 要 复 制 到 目 标 对 象 也 可 以 像 下 面 这 样 使 用 一 连 串 的 = 运 算 符 : obj3 = obj2 = obj1; 习 题 1. 运 算 符 重 载 的 规 则 有 哪 些? 2. 有 哪 些 运 算 符 不 能 重 载? 3. 运 算 符 重 载 的 形 式 有 哪 些? 各 有 何 特 点? 4. 生 成 一 个 复 数 类 Complex, 复 数 的 实 部 和 虚 部 分 别 为 double 型 x 和 y 重 载 运 算 符 加 减 乘 除 为 类 的 成 员 函 数, 用 来 计 算 两 个 复 数 的 加 减 乘 除 运 算 5. 分 析 该 程 序 的 输 出 结 果, 学 会 重 载 运 算 符 的 方 法 #include"iostream.h"
164 第 8 章 运 算 符 重 载 155 class point public: point(int i,int j) x=i;y=j; void print() cout<<'('<<x<<','<<y<<')'<<endl; void operator+=(point p) x+=p.x; y+=p.y; void operator =(point p) x =p.x; y =p.y; private: int x,y; ; void main() point p1(5,7),p2(4,3); p1.print(); p2.print(); p1+=p2; p1.print(); p2 =p1; p2.print(); 6. 写 出 下 列 的 程 序 的 执 行 结 果 分 析 重 载 的 () 的 运 算 符 的 功 能 #include"iostream.h" class A public: double operator ()(double x,double y) const; ; double A::operator ()(double x,double y) const return (x+5)*(y+1);
165 156 C++ 程 序 设 计 void main() A a; cout<<a(2.5,7.2)<<endl; 7. 在 date 类 ( 包 括 年, 月, 日 ) 中 重 载 +=, 计 算 一 个 整 数 和 一 个 date 类 对 象 之 和, 并 且 返 回 date 类 对 象 例 如 在 1997 年 2 月 20 日, 求 出 经 过 100 天 以 后 的 日 期 8. 生 成 时 间 类 Time 类 的 每 个 成 员 包 含 私 有 数 据 成 员 h,m 和 s, 分 别 表 示 当 前 时 刻 的 小 时 分 钟 和 秒 提 供 成 员 函 数 displayt(), 显 示 当 前 时 刻, 重 载 ++, 为 Time 类 的 成 员 函 数, 分 别 表 示 将 当 前 时 刻 推 后 和 提 前 一 个 小 时 时 间 的 表 示 采 用 24 小 时 制
166 第 9 章 继 承 性 继 承 性 是 面 向 对 象 程 序 设 计 的 一 种 重 要 功 能, 是 实 现 代 码 复 用 的 一 种 形 式 继 承 可 以 使 程 序 设 计 人 员 在 一 个 已 存 在 类 的 基 础 上 很 快 建 立 一 个 新 的 类, 而 不 必 从 零 开 始 设 计 新 类 新 设 计 类 能 够 具 有 原 有 类 的 属 性 和 方 法, 并 且 为 了 使 新 类 具 有 自 己 独 特 的 功 能, 新 类 还 要 添 加 新 的 属 性 和 方 法 当 一 个 类 被 其 他 的 类 继 承 时, 被 继 承 的 类 称 为 基 类, 又 称 为 父 类 超 类 继 承 其 他 类 属 性 和 方 法 的 类 称 为 派 生 类, 又 称 为 子 类 继 承 类 9.1 基 类 和 派 生 类 派 生 类 的 定 义 派 生 能 用 从 派 生 类 到 基 类 的 箭 头 图 形 表 示, 箭 头 指 向 基 类 表 示 派 生 类 引 用 基 类 中 的 函 数 和 数 据, 而 基 类 则 不 能 访 问 派 生 类, 如 图 9-1 所 示 任 何 一 个 类 均 可 作 为 基 类 仅 从 一 个 基 类 派 生 的 继 承 称 为 单 继 承 单 继 承 声 明 语 句 的 一 般 形 式 为 : class < 派 生 类 名 > : < 继 承 方 式 > < 基 类 名 > 数 据 成 员 和 成 员 函 数 声 明 基 类 派 生 类 图 9-1 派 生 其 中,< 派 生 类 名 > 是 定 义 的 新 类 的 名 字, 它 是 从 基 类 中 派 生 的, 并 且 按 照 指 定 的 继 承 方 式 进 行 继 承 < 继 承 方 式 > 有 如 下 3 种 : public 表 示 公 有 继 承 方 式 private 表 示 私 有 继 承 方 式 protected 表 示 保 护 继 承 方 式 基 类 可 分 为 两 类 : 直 接 基 类 和 间 接 基 类 如 果 某 个 基 类 在 基 类 列 表 中 提 及, 则 称 它 是 直 接 基 类 例 如 : class A ; class B:public A // 类 A 为 直 接 基 类 ; 间 接 基 类 可 写 为 :
167 158 C++ 程 序 设 计 class A ; class B:public A ; class C:public B ; // 类 A 是 间 接 基 类, 可 扩 展 到 任 意 级 数 继 承 方 式 继 承 方 式 有 3 种 : 公 有 继 承 方 式 (public) 私 有 继 承 方 式 (private) 和 保 护 继 承 方 式 (protected) 1. 公 有 继 承 在 公 有 继 承 下, 基 类 的 公 有 成 员 在 派 生 类 中 仍 是 公 有 的 派 生 类 的 对 象 可 以 直 接 使 用 基 类 所 有 的 公 有 方 法, 除 非 这 些 方 法 在 派 生 类 中 已 经 被 重 新 定 义 基 类 的 被 保 护 成 员 在 派 生 类 中 仍 被 保 护 基 类 的 私 有 成 员 虽 然 被 派 生 类 继 承, 但 是 仍 旧 保 持 基 类 的 私 有 属 性, 所 以 派 生 类 的 成 员 不 能 直 接 访 问 它 派 生 类 继 承 了 在 其 基 类 中 声 明 的 数 据 结 构, 在 派 生 类 中 的 数 据 成 员 和 成 员 函 数 的 声 明 中 不 用 再 声 明 能 被 继 承 的 数 据 结 构, 而 只 需 声 明 派 生 类 中 没 有 的 数 据 结 构 同 样, 派 生 类 也 继 承 了 基 类 的 公 有 成 员 函 数 在 公 有 派 生 类 中 : (1) 基 类 的 公 有 成 员 在 派 生 类 中 仍 是 公 有 成 员 (2) 基 类 的 保 护 成 员 在 派 生 类 中 仍 是 保 护 成 员 (3) 基 类 的 私 有 成 员 在 派 生 类 中 是 不 可 访 问 的 2. 私 有 继 承 在 私 有 继 承 情 况 下, 基 类 的 所 有 成 员 称 为 派 生 类 的 私 有 成 员 基 类 的 私 有 成 员 被 继 承 后, 派 生 仍 不 能 访 问 它 这 说 明 在 程 序 中 不 能 访 问 派 生 类 的 对 象 中 继 承 来 的 基 类 的 任 何 成 员 在 私 有 派 生 类 中 : (1) 基 类 的 公 有 成 员 在 派 生 类 中 是 私 有 成 员 (2) 基 类 的 保 护 成 员 在 派 生 类 中 是 私 有 成 员 (3) 基 类 的 私 有 成 员 在 派 生 类 中 仍 是 不 可 访 问 的 3. 保 护 继 承 希 望 一 个 派 生 类 能 访 问 基 类 的 成 员, 但 又 不 想 把 基 类 的 这 些 成 员 声 明 为 公 有 的, 最 好 的 方 法 是 在 基 类 的 定 义 中 使 用 保 护 继 承 在 基 类 的 保 护 部 分 定 义 的 任 何 成 员 在 其 派 生 类 的 作 用 域 内 都 可 以 被 看 作 是 公 用 的, 而 在 程 序 的 其 他 部 分 是 私 有 的 换 句 话 说, 保 护 成 员 对 它 的 派 生 类 的 成 员 函 数 而 言, 它 是 公 有 成 员, 但 对 成 员 在 类 之 外 定 义 的 其 他 类 或 函 数 而 言, 它 是 私 有 成 员 在 保 护 派 生 类 中 : (1) 基 类 的 公 有 成 员 在 派 生 类 中 是 保 护 成 员 (2) 基 类 的 保 护 成 员 在 派 生 类 中 是 保 护 成 员 (3) 基 类 的 私 有 成 员 在 派 生 类 中 仍 是 不 可 访 问 的
168 第 9 章 继 承 性 单 继 承 中 的 成 员 访 问 权 限 9.2 单 继 承 类 中 的 成 员 有 不 同 的 访 问 权 限 (1) 公 有 成 员 : 一 个 类 的 公 有 成 员 允 许 本 类 的 成 员 函 数 本 类 的 对 象 公 有 派 生 类 的 成 员 函 数 以 及 公 有 派 生 类 的 对 象 访 问 (2) 私 有 成 员 : 一 个 类 的 私 有 成 员 只 允 许 本 类 的 成 员 函 数 访 问 (3) 保 护 成 员 : 具 有 私 有 成 员 和 公 有 成 员 的 特 征 一 个 类 的 保 护 成 员 允 许 本 类 的 成 员 函 数 公 有 派 生 类 的 成 员 函 数 访 问, 本 类 的 对 象 公 有 派 生 类 的 对 象 不 能 访 问 例 9.1 成 员 访 问 权 限 举 例 class A // 基 类 private: int priva; protected: int prota; public: int puba; ; class B : public A // 派 生 类 public: void fn() int a; a = priva; // 错 误 : 不 可 访 问 a = prota; // 有 效 a = puba; // 有 效 ; void main() A a; // 基 类 对 象 a.priva = 1; // 错 误 : 不 可 访 问 a.prota = 1; // 错 误 : 不 可 访 问 a.puba = 1; // 有 效 B b; // 派 生 类 对 象 b.priva = 1; // 错 误 : 不 可 访 问
169 160 C++ 程 序 设 计 b.prota = 1; b.puba = 1; 例 9.2 分 析 下 面 的 程 序 #include "iostream.h" class A private: int x; public: void f1(int a); int f2(); ; class B:public A private: int y; public: void g1(int a); int g2(); ; void A::f1(int a) x=a; int A::f2() return x; void B::g1(int a) y=a; int B::g2() return y+f2(); void main() // 错 误 : 不 可 访 问 // 有 效
170 第 9 章 继 承 性 161 B b; b.f1(10); b.g1(10); cout<<b.g2()<<endl; 运 行 程 序, 输 出 结 果 为 : 构 造 函 数 和 析 构 函 数 1. 构 造 函 数 派 生 类 的 数 据 是 由 基 类 中 的 数 据 和 在 派 生 类 中 新 定 义 的 数 据 组 成 的 由 于 构 造 函 数 不 能 够 继 承, 因 此, 在 定 义 派 生 类 的 构 造 函 数 时, 除 了 对 自 己 新 定 义 的 数 据 成 员 进 行 初 始 化 外, 还 必 须 调 用 基 类 的 构 造 函 数 使 基 类 的 数 据 成 员 得 以 初 始 化 例 9.3 分 析 下 面 的 程 序 class Base protected: int a; public: Base() a = 0; // 默 认 构 造 函 数 Base(int c) a = c; // 单 参 数 构 造 函 数 ; class Derived: public Base public: Derived():Base(); // 默 认 构 造 函 数 Derived(int c):base(c); // 单 参 数 构 造 函 数 ; 当 声 明 派 生 类 的 某 一 对 象 时, 用 如 下 语 句 : Derived obj; 首 先 调 用 基 类 的 构 造 函 数, 然 后 调 用 派 生 类 的 构 造 函 数 基 类 构 造 函 数 在 派 生 类 构 造 函 数 后 给 出, 并 用 冒 号 分 隔, 例 如 : Derived(): Base() 在 调 用 派 生 类 的 构 造 函 数 过 程 中, 可 明 确 选 择 应 调 用 基 类 的 哪 一 种 构 造 函 数 例 如 : Derived obj1(20); 调 用 Derived 中 的 一 个 参 数 的 构 造 函 数 这 一 构 造 函 数 也 调 用 基 类 中 的 相 应 构 造 函 数 例 如 : Derived(int c):base(c); // 传 递 参 数 c 给 Base 当 继 承 类 将 另 一 个 类 的 对 象 作 为 其 成 员 包 括 在 内 时, 继 承 类 的 构 造 函 数 还 包 含 对 子 对 象 初 始 化 的 构 造 函 数 例 9.4 分 析 下 面 的 程 序 class engine
171 162 C++ 程 序 设 计 private: int num; public: engine(int s) num = s; ; class jet private: int jt; engine eobj; // 这 里 声 明 一 个 对 象 public: jet(int x, int y): eobj(y) jt = x; ; 在 jet 类 的 构 造 函 数 中,engine 类 对 象 的 名 字 写 在 冒 号 的 后 面 它 告 诉 编 译 器 用 y 值 初 始 化 jet 类 的 eobj 数 据 成 员 这 就 与 用 语 句 engine eobj(y) 声 明 类 engine 的 对 象 相 似 任 何 数 据 类 型 的 变 量 均 能 这 样 初 始 化, 如 int(i); 总 结 派 生 类 的 构 造 函 数 的 调 用 顺 序 如 下 (1) 基 类 的 构 造 函 数 (2) 子 对 象 类 的 构 造 函 数 ( 如 果 子 对 象 存 在 ) (3) 派 生 类 的 构 造 函 数 2. 析 构 函 数 析 构 函 数 的 调 用 顺 序 与 构 造 函 数 相 反, 析 构 函 数 首 先 为 派 生 类 调 用, 然 后 为 子 对 象 类 的 析 构 函 数 调 用, 最 后 调 用 基 类 的 析 构 函 数 仅 当 派 生 类 的 构 造 函 数 通 过 动 态 内 存 管 理 分 配 内 存 时, 才 定 义 派 生 类 的 析 构 函 数 如 果 派 生 类 的 构 造 函 数 不 起 任 何 作 用 或 派 生 类 中 未 添 加 任 何 附 加 数 据 成 员, 则 派 生 类 的 析 构 函 数 可 以 是 一 个 空 函 数 例 9.5 分 析 下 面 的 程 序 #include "iostream.h" class A private: int x; public: A()x=0; A(int xx)x=xx; ~A()cout<<"A Destructor called."<<endl;
172 第 9 章 继 承 性 163 void display()cout<<x<<" "; ; class B:public A private: int b1; A b2; // 这 里 声 明 一 个 对 象 public: B()b1=0; B(int i,int j):b2(j)b1=i; B(int i, int j,int k): A(i),b2(j),b1(k) ~B()cout<<"B Destructor called."<<endl; void print() display(); cout<<b1<<" "; b2.display(); cout<<endl; ; void main() B obj1; B obj2(5,6); B obj3(7,8,9); obj1.print(); obj2.print(); obj3.print(); 程 序 运 行 结 果 为 : B Destructor called. A Destructor called. A Destructor called. B Destructor called. A Destructor called. A Destructor called.
173 164 C++ 程 序 设 计 B Destructor called. A Destructor called. A Destructor called. 3. 调 用 成 员 函 数 派 生 类 中 的 成 员 函 数 与 基 类 中 的 成 员 函 数 可 以 有 相 同 的 名 称 当 使 用 基 类 的 对 象 调 用 函 数 时, 基 类 的 函 数 被 调 用 当 使 用 派 生 类 对 象 的 名 称 时, 派 生 类 的 函 数 被 调 用 如 果 派 生 类 的 成 员 函 数 要 调 用 相 同 名 称 的 基 类 函 数, 它 必 须 使 用 作 用 域 运 算 符 :: 基 类 中 的 函 数 既 可 使 用 基 类 的 对 象, 也 可 使 用 派 生 类 的 对 象 调 用 如 果 函 数 存 在 于 派 生 类 而 不 是 基 类 中, 那 么 它 只 能 被 派 生 类 的 对 象 调 用 例 9.6 分 析 下 面 的 程 序 class Base protected: int ss; public: int func() return ss; void print()cout<<ss; ; class Derived: public Base public: int func() return Base::func(); ; void main() Base b1; // 基 类 对 象 b1.func(); // 调 用 基 类 函 数 func Derived a1; // 派 生 类 对 象 a1.func(); // 调 用 派 生 类 对 象 func 9.3 多 继 承 多 继 承 的 概 念 从 多 个 基 类 派 生 的 继 承 称 为 多 继 承, 或 称 多 重 继 承, 即 一 个 派 生 类 可 以 有 多 个 直 接 基 类 派 生 类 与 每 个 基 类 之 间 的 关 系 仍 看 作 是 一 个 单 继 承 关 系, 满 足 单 继 承 的 规 则 多 继 承 声 明 语 句 的 一 般 形 式 为 : class < 派 生 类 名 >:< 继 承 方 式 > < 基 类 名 1>,< 继 承 方 式 > < 基 类 名 2>,
174 第 9 章 继 承 性 165 数 据 成 员 和 成 员 函 数 声 明 ; 例 如 : class A ; class B ; class C:public A,public B ; 其 中, 派 生 类 C 具 有 两 个 直 接 基 类 派 生 类 C 的 成 员 包 含 基 类 A 中 的 成 员 和 基 类 B 中 的 成 员 以 及 该 类 本 身 的 成 员 例 9.7 分 析 下 面 的 程 序 #include "iostream.h" class A public: void printa()cout<<"hello "; ; class B public: void printb()cout<<"c++ "; ; class C: public A,public B public: void printc()cout<<"world!\n"; ; void main() C obj; obj.printa(); obj.printb();
175 166 C++ 程 序 设 计 obj.printc(); 程 序 执 行 结 果 为 : Hello C++ World! 多 继 承 的 构 造 函 数 和 析 构 函 数 派 生 类 也 可 以 作 为 基 类 供 别 的 类 继 承, 这 样 就 产 生 了 多 层 次 的 继 承 关 系 在 此 情 况 下, 原 始 的 基 类 可 以 称 为 第 二 个 派 生 类 的 间 接 基 类 派 生 类 也 可 以 直 接 继 承 多 个 基 类, 此 时, 多 个 基 类 联 合 创 建 了 一 个 派 生 类 类 的 层 次 结 构 也 称 继 承 链 如 果 A 被 B 继 承,B 被 C 继 承, 那 么,A 称 为 C 的 间 接 基 类 间 接 基 类 的 构 造 函 数 最 先 被 调 用, 接 下 来 被 调 用 的 是 直 接 基 类 的 构 造 函 数, 最 后 是 继 承 类 的 构 造 函 数 析 构 函 数 的 调 用 顺 序 正 好 相 反 当 一 个 派 生 类 继 承 有 层 次 的 类 时, 继 承 链 上 的 每 个 派 生 类 必 须 将 它 需 要 的 变 量 传 递 给 它 的 基 类 多 基 派 生 类 的 构 造 函 数 的 一 般 形 式 为 : < 派 生 类 名 >::< 派 生 类 名 >( 参 数 表 1, 参 数 表 2, ):< 基 类 名 1>( 参 数 表 1 ),< 基 类 名 2>( 参 数 表 2 ), < 派 生 类 成 员 > 多 重 继 承 的 构 造 函 数 按 照 下 面 的 原 则 被 调 用 (1) 先 基 类, 后 自 己 (2) 如 果 在 同 一 层 上 有 多 个 基 类, 按 照 派 生 时 定 义 的 先 后 顺 序 执 行 多 重 继 承 的 析 构 函 数 的 执 行 顺 序 与 多 重 继 承 的 构 造 函 数 的 执 行 顺 序 相 反 例 9.8 分 析 下 列 程 序 的 输 出 结 果 #include "iostream.h" class Base1 private: int a1; public: Base1(int i)a1=i;cout<<"constructor Base1 called "<<a1<<endl; ~Base1()cout<<"Desstructor Base1 called"<<endl; ; class Base2 private: int a2; public:
176 第 9 章 继 承 性 167 Base2(int j)a2=j;cout<<"constructor Base2 called "<<a2<<endl; ~Base2()cout<<"Desstructor Base2 called"<<endl; ; class Base3 private: int a3; public: Base3(int k=0)a3=k;cout<<"constructor Base3 called "<<a3<<endl; ~Base3()cout<<"Desstructor Base3 called"<<endl; ; class Derived:public Base3,public Base1,public Base2 private: int a4; Base1 obj1; Base2 obj2; Base3 obj3; public: Derived(int i,int j,int k,int m,int n):obj2(m),obj3(j),obj1(k),base2(i),base1(j) a4=n; cout<<"constructor Derived called "<<a4<<endl; ~Derived()cout<<"Desstructor Derived called"<<endl; ; void main() Derived obj(1,2,3,4,5); 程 序 输 出 结 果 : Constructor Base3 called 0 Constructor Base1 called 2 Constructor Base2 called 1 Constructor Base1 called 3 Constructor Base2 called 4 Constructor Base3 called 2 Constructor Derived called 5 Desstructor Derived called
177 168 C++ 程 序 设 计 Desstructor Base3 called Desstructor Base2 called Desstructor Base1 called Desstructor Base2 called Desstructor Base1 called Desstructor Base3 called 注 意 : 执 行 基 类 构 造 函 数 的 顺 序 取 决 于 定 义 派 生 类 时 基 类 的 顺 序 在 派 生 类 构 造 函 数 的 成 员 初 始 化 列 表 中 各 项 顺 序 可 以 任 意 地 排 列 二 义 性 问 题 一 般 说 来, 在 派 生 类 中 对 基 类 成 员 的 访 问 应 该 是 惟 一 的 但 是 在 多 继 承 情 况 下, 当 两 个 基 类 有 相 同 的 函 数 或 数 据 成 员 名 称 时, 编 译 器 将 不 能 理 解 使 用 哪 个 函 数, 出 现 对 基 类 成 员 访 问 不 惟 一 的 情 况, 称 为 对 基 类 成 员 访 问 的 二 义 性 问 题 例 如 : class Alpha public: void display(); ; class Beta public: void display(); ; class Gamma: public Alpha,public Beta ; void main() Gamma obj; obj.display(); // 含 义 模 糊 : 不 能 编 译 若 要 访 问 正 确 的 函 数 或 数 据 成 员, 需 要 使 用 作 用 域 运 算 符 :: 例 如 : obj.alpha::display(); obj.beta::display(); 应 当 由 编 程 人 员 来 避 免 此 类 冲 突 和 多 义 性 在 编 程 时, 通 过 在 派 生 类 中 定 义 一 个 新 函 数 display() 可 以 解 决 这 个 问 题 例 如 : void Gamma::display() Alpha::display();
178 第 9 章 继 承 性 169 Beta::display(); 这 样 一 来, 编 译 器 会 检 测 名 称 冲 突, 并 予 以 解 决 在 多 继 承 情 况 下, 存 在 很 多 可 以 放 入 继 承 的 组 合, 有 可 能 将 一 个 类 不 止 一 次 地 用 作 基 类 例 如 : class Teacher:public Person private: int x; public: Teacher()x =0; // 构 造 函 数 Teacher(int s) x = s; ; class Student:public Person private: int y; public: Student()y = 0; // 构 造 函 数 Student(int a) y = a; ; class Teach_assistant: public Teacher,public Student private: int z; public: Teach_asst():Teacher(),Student() z = 0; // 构 造 函 数 Teach_asst(int s,int a,int b):teacher(s),student(a) z = b; ; Teacher 类 和 Student 类 都 含 有 Person 类 成 员 的 副 本 当 Teach_assistant 类 从 Teacher 类 和 Student 类 派 生 时, 它 含 有 两 个 类 的 数 据 成 员 的 副 本 这 意 味 着 它 含 有 Person 类 成 员 的 两 份 副 本, 一 份 来 自 Teacher 类, 一 份 来 自 Student 类 这 就 在 基 类 数 据 成 员 之 间 出 现 了 多 义 性 当 声 明 一 个 Teaching_assistant 类 对 象 时 将 两 次 调 用 Person 类 对 Person 类 的 成 员 进 行 访 问 时, 可 能 会 出 现 二 义 性 如 果 要 想 使 这 个 公 共 基 类 Person 类 在 派 生 类 中 只 产 生 一 个 基 类 子 对 象, 则 必 须 将 这 个 基 类 定 义 为 虚 基 类 9.4 虚 基 类 虚 基 类 的 引 入 和 说 明 多 重 继 承 层 次 结 构 可 能 很 复 杂, 而 且 可 能 会 导 致 出 现 这 种 情 况, 即 派 生 类 从 同 一 基 类 中 继
179 170 C++ 程 序 设 计 承 多 次, 这 样 一 来 就 会 出 现 基 类 的 两 个 或 两 个 以 上 的 副 本, 编 译 器 不 知 道 应 该 访 问 哪 个 副 本, 造 成 二 义 性 问 题, 因 此 就 会 发 生 错 误 为 了 避 免 出 现 基 类 的 两 个 副 本, 应 使 用 虚 基 类 事 实 上, 引 入 虚 基 类 就 是 为 了 解 决 二 义 性 问 题 虚 基 类 说 明 格 式 如 下 : virtual < 继 承 方 式 >< 基 类 名 > 其 中,virtual 是 虚 基 类 的 关 键 字 例 如 : class window protected: int basedata; ; class border: virtual public window ; class menu: virtual public window ; class border_and_menu: public border, public menu public: int show() return basedata; ; 虚 基 类 用 在 多 重 继 承 层 次 结 构 中, 避 免 同 一 数 据 成 员 的 不 必 要 重 复 虚 基 类 的 构 造 函 数 虚 基 类 的 出 现 改 变 了 构 造 函 数 的 调 用 顺 序 在 初 始 化 任 何 非 虚 基 类 之 前, 将 先 初 始 化 虚 基 类 如 果 存 在 多 个 虚 基 类, 初 始 化 顺 序 由 它 们 在 继 承 图 中 的 位 置 决 定, 其 顺 序 是 从 上 到 下 从 左 到 右 调 用 析 构 函 数 遵 守 相 同 的 规 则, 但 是 顺 序 相 反 例 9.9 分 析 下 列 程 序 的 输 出 结 果 #include "iostream.h" class A public: A(const char *s1)cout<<s1<<endl; ~A()cout<<"Destructor A called"<<endl; ; class B:virtual public A
180 第 9 章 继 承 性 171 public: B(const char *s1,const char *s2):a(s1)cout<<s2<<endl; ~B()cout<<"Destructor B called"<<endl; ; class C:virtual public A public: C(const char *s1,const char *s2):a(s1)cout<<s2<<endl; ~C()cout<<"Destructor C called"<<endl; ; class D:public B,public C public: D(const char *s1,const char *s2,const char *s3,const char *s4):b(s1,s2),c(s1,s3),a(s1) cout<<s4<<endl; ~D()cout<<"Destructor D called"<<endl; ; void main() D obj("class A","class B","class C","class D"); 程 序 运 行 结 果 为 : class A class B class C class D Destructor D called Destructor C called Destructor B called Destructor A called 虚 基 类 的 应 用 例 9.10 设 计 一 个 表 示 在 职 学 生 的 类, 分 析 下 列 程 序 的 输 出 结 果 首 先 设 计 基 类 people, 表 示 一 般 人 员 的 信 息 ; 再 设 计 一 个 表 示 工 作 人 员 的 类 job; 接 下 来 设 计 一 个 表 示 学 生 的 类 student, 在 职 学 生 类 以 这 些 类 为 基 类 #include "iostream.h" #include "string.h"
181 172 C++ 程 序 设 计 class people private: char name[20]; char ID[20]; char sex; int age; public: people(char *n="",char *i="",char s='m',int a=19); void pdisplay(); ; people::people(char *n,char *i,char s,int a) strcpy(name,n); strcpy(id,i); sex=s; age=a; void people::pdisplay() cout<<" 人 员 :\n 身 份 证 号 ---"<<ID<<endl; cout<<" 姓 名 ---"<<name<<endl; if(sex=='m' sex=='m')cout<<" 性 别 ---"<<" 男 "<<endl; else if(sex=='f' sex=='f')cout<<" 性 别 ---"<<" 女 "<<endl; cout<<" 年 龄 ---"<<age<<endl; class job:virtual public people private: int number; // 工 作 证 号 char department[20]; // 工 作 部 门 public: job(char *n,char *i,char s,int a,int num=0,char *dep=""); void jdisplay(); ; job::job(char *n,char *i,char s,int a,int num,char *dep):people(n,i,s,a) number=num;
182 第 9 章 继 承 性 173 strcpy(department,dep); void job::jdisplay() cout<<" 工 作 人 员 :"<<endl; cout<<" 编 号 ---"<<number<<endl; cout<<" 工 作 单 位 ---"<<department<<endl; class student: virtual public people private: int snum; int classnum; public: student(char *n,char *i,char s,int a,int sn=0,int cn=0):people(n,i,s,a) snum=sn; classnum=cn; void sdisplay() cout<<" 在 校 学 生 "<<endl; cout<<" 学 号 ="<<snum<<endl; cout<<" 班 级 ="<<classnum<<endl; ; class job_student:public job,public student public: job_student(char *n,char *i,char s='m',int a=19,int mn=0,char *md="",int no=0,int sta=1):job(n,i,s,a,mn,md),student(n,i,s,a,no,sta),people(n,i,s,a) void tdisplay(); ; void job_student::tdisplay() cout<<" 在 职 学 生 "<<endl;
183 174 C++ 程 序 设 计 void main() job_student w(" 张 国 媛 "," ",'f',22,102," 民 族 学 院 ",5282,2004); w.tdisplay(); w.pdisplay(); w.jdisplay(); w.sdisplay(); 程 序 运 行 结 果 为 : 在 职 学 生 人 员 : 身 份 证 号 姓 名 --- 张 国 媛 性 别 --- 女 年 龄 工 作 人 员 : 编 号 工 作 单 位 --- 民 族 学 院 在 校 学 生 学 号 =5282 班 级 =2004 习 题 1. 在 C++ 中, 类 的 继 承 格 式 是 怎 样 的? 2. 在 C++ 中, 类 的 继 承 分 为 哪 些 类? 继 承 方 式 分 为 哪 几 种? 3. 派 生 类 构 造 函 数 执 行 的 次 序 是 怎 样 的? 4. 引 入 虚 基 类 就 是 为 了 解 决 什 么 问 题? 怎 样 定 义 虚 基 类? 带 有 虚 基 类 的 派 生 类 的 构 造 函 数 有 什 么 特 点? 5. 如 何 定 义 单 继 承 的 派 生 类? 如 何 定 义 多 继 承 的 派 生 类? 6. 下 图 是 面 向 对 象 的 类 层 次 结 构, 编 写 类, 实 现 它 们 之 间 的 继 承 关 系 Person Employee Contractor WagedEmployee SalariedEmployee 7. 定 义 Box 类 描 述 立 方 体,ColoredBox 类 描 述 彩 色 立 方 体,ColoredBox 类 继 承 了 Box 类
184 第 9 章 继 承 性 175 的 一 些 特 性 8. 建 立 一 般 的 基 类 Building, 用 来 存 储 一 座 楼 房 的 层 数 房 间 数 以 及 它 的 面 积 数 ; 建 立 派 生 类 House, 继 承 Building, 并 存 储 卧 室 和 洗 澡 室 的 数 量, 再 建 立 派 生 类 Office, 继 承 House, 并 存 储 灭 火 器 和 电 话 数 9. 写 出 下 列 程 序 的 执 行 结 果 #include"iostream.h" class shape public: void Draw() cout<<"\nbase::draw()\n"; void Erase() cout<<"base::erase()\n\n"; shape() Draw(); ~shape() Erase(); ; class Polygon:public shape public: Polygon() Draw(); void Draw() cout<<"polygon::draw()\n"; void Erase() cout<<"polygon::erase()\n"; ~Polygon() Erase(); ; class Rectangle:public Polygon public: Rectangle()Draw(); void Draw()cout<<"Rectangle::Draw()\n"; void Erase()cout<<"Rectangle::Erase()\n"; ~Rectangle()Erase(); ; class Square:public Rectangle public: Square() Draw(); void Draw() cout<<"square::draw()\n"; void Erase() cout<<"square::erase()\n"; ~Square() Erase(); ; void main()
185 176 C++ 程 序 设 计 Polygon c; Rectangle s; Square t; cout<<" \n"; 10. 定 义 B0 是 虚 基 类,B1 和 B2 都 继 承 B0,D1 同 时 继 承 B1 和 B2, 他 们 都 是 公 有 派 生, 这 些 类 都 有 同 名 的 公 有 数 据 成 员 和 公 有 函 数 编 制 主 程 序, 生 成 D1 的 对 象, 通 过 限 定 词 :: 分 别 访 问 D1,B0,B1,B2 的 公 有 成 员 11. 分 析 下 列 程 序 的 访 问 权 限, 并 回 答 问 题 #include"iostream.h" class A public: void f1(); protected: int j1; private: int i1; ; class B:public A public: void f2(); protected: int j2; private: int i2; ; class C:public B public: void f3(); ; 回 答 下 列 问 题 : (1) 派 生 类 B 中 成 员 函 数 f2() 能 否 访 问 基 类 A 中 的 成 员 f1(),i1 和 j1 呢? (2) 派 生 类 B 的 对 象 b1 能 否 访 问 基 类 A 中 的 成 员 f1(),i1 和 j1 呢? (3) 派 生 类 C 中 成 员 函 数 f3() 能 否 访 问 直 接 基 类 B 中 的 成 员 f2() 和 j2 呢? 能 否 访 问 间 接 基 类 A 中 的 成 员 f1(),i1 和 j1 呢?
186 第 9 章 继 承 性 177 (4) 类 C 的 对 象 c1 能 否 访 问 直 接 基 类 B 中 的 成 员 f2(),i2 和 j2 呢? 能 否 访 问 间 接 基 类 A 中 的 成 员 f1(),i1 和 j1 呢? (5) 从 (1)~(4) 问 题 可 得 出 对 公 有 继 承 的 什 么 结 论? 12. 编 写 程 序 对 大 学 里 的 人 员 进 行 管 理 大 学 里 的 人 员 主 要 由 学 生 教 师 ( 教 课 ) 教 员 ( 不 教 课 ) 和 在 职 进 修 教 师 ( 既 当 学 生 又 当 教 师 ) 组 成, 各 类 人 员 均 有 姓 名 电 话 和 地 址 等 信 息, 学 生 还 有 专 业 信 息, 在 职 人 员 另 有 所 在 部 门 及 工 资 信 息, 教 师 另 有 教 授 课 程 信 息, 在 职 进 修 教 师 具 备 以 上 各 类 人 员 的 信 息 系 统 的 类 层 次 结 构 如 下 : Person Student Staff Teacher StudentTeacher
187 第 10 章 虚 函 数 和 多 态 性 多 态 性 是 面 向 对 象 的 最 重 要 特 征 之 一, 多 态 性 增 加 了 面 向 对 象 软 件 系 统 的 扩 展 功 能, 提 高 了 软 件 的 可 重 用 性 多 态 是 指 不 同 对 象 对 相 同 消 息 作 出 不 同 的 响 应, 多 态 是 通 过 继 承 虚 函 数 以 及 动 态 联 编 来 实 现 的 使 用 此 特 性 可 以 为 用 户 提 供 通 用 程 序 的 框 架, 用 户 可 以 利 用 继 承 性 继 承 程 序 框 架, 利 用 多 态 性 来 丰 富 程 序 框 架 10.1 虚 函 数 虚 函 数 的 定 义 虚 函 数 是 实 际 上 不 存 在, 但 确 实 影 响 程 序 某 些 部 分 的 函 数 虚 函 数 和 派 生 类 联 系 在 一 起, 它 有 多 态 性, 即 派 生 的 类 有 共 同 的 函 数 这 些 共 同 的 函 数 有 着 相 同 的 函 数 名 称 和 相 同 的 参 数, 但 是 却 有 各 自 不 同 的 具 体 实 现 部 分 虚 函 数 的 定 义 方 法 如 下 : virtual < 函 数 返 回 类 型 >< 虚 函 数 名 称 ><( 参 数 列 表 )>; 定 义 虚 函 数 要 遵 循 下 列 规 则 (1) 类 的 静 态 成 员 函 数 不 可 以 定 义 为 虚 函 数 (2) 类 的 构 造 函 数 不 可 以 定 义 为 虚 函 数 (3) 非 类 的 成 员 函 数 不 可 以 定 义 为 虚 函 数 例 10.1 假 设 一 个 程 序 可 用 来 绘 制 不 同 的 形 状, 比 如 三 角 形 圆 矩 形 和 椭 圆 等, 并 假 设 这 些 类 中 每 个 类 都 有 一 个 成 员 函 数 draw(), 通 过 该 函 数 可 绘 制 对 象 分 析 下 列 程 序 的 输 出 结 果 #include "iostream.h" class person public: void printinfo() // 基 类 中 的 函 数 cout<<"person\n"; ; class worker: public person
188 第 10 章 虚 函 数 和 多 态 性 179 private: int kindofwork; public: void printinfo () // 在 派 生 类 worker 中 重 新 定 义 cout<<"worker\n"; ; class teacher: public person private: int subject; public: void printinfo () // 在 派 生 类 teacher 中 重 新 定 义 cout<<"teacher\n"; ; void main() worker w; teacher t; person* p; p = &w; // w 是 worker 类 对 象 p >printinfo(); p = &t; p >printinfo(); 程 序 的 执 行 结 果 为 : Person Person 语 句 p = &w 把 派 生 类 地 址 分 配 给 基 类 指 针 当 调 用 printinfo() 函 数 时, 使 用 p >printinfo() 语 句 希 望 调 用 派 生 类 的 printinfo() 函 数, 但 实 际 上 调 用 的 是 基 类 的 printinfo() 函 数 想 根 据 指 针 p 所 指 向 的 对 象, 通 过 函 数 调 用 来 输 出 worker 信 息 或 任 何 其 他 对 象 信 息 即 由 相 同 的 函 数 调 用 执 行 不 同 的 printinfo() 函 数 要 求 所 有 不 同 的 子 类 都 必 须 从 单 一 基 类 person 中 派 生 在 基 类 中,printInfo () 函 数 必 须 声 明 成 virtual 类 型 在 每 个 派 生 类 中, 可 以 重 新 定 义 printinfo() 函 数 例 如 : class person
189 180 C++ 程 序 设 计 public: virtual void printinfo() // 基 类 中 的 虚 函 数 cout<<"person\n"; ; 将 printinfo() 函 数 定 义 为 虚 函 数, 执 行 上 面 程 序 的 结 果 为 : Worker Teacher 使 用 p 指 针 调 用 同 一 函 数 printinfo(), 运 行 时 根 据 p 具 体 值 执 行 不 同 的 函 数 注 意 : 虚 函 数 应 该 在 基 类 中 声 明, 且 不 能 在 派 生 类 中 重 新 定 义 如 果 使 用 派 生 类 层 次 结 构, 必 须 在 最 高 层 上 声 明 虚 函 数 虚 函 数 必 须 定 义 在 它 第 一 次 被 声 明 的 类 中 在 派 生 类 中 重 新 定 义 的 虚 函 数 必 须 和 基 类 中 的 虚 函 数 有 相 同 的 参 数 个 数 和 数 据 类 型, 否 则, 编 译 器 将 认 为 重 载 虚 函 数 虚 函 数 是 动 态 联 编 的 基 础, 如 果 某 个 类 中 的 一 个 成 员 函 数 被 说 明 为 虚 函 数, 则 当 使 用 这 个 成 员 函 数 操 作 指 针 或 引 用 所 标 示 的 对 象 时, 对 该 成 员 函 数 调 用 采 用 动 态 联 编 的 方 式, 即 在 运 行 时 进 行 关 联 或 束 定 虚 成 员 函 数 是 动 态 ( 在 运 行 时 ) 联 编 的, 即 成 员 函 数 是 根 据 对 象 类 型 而 不 是 指 向 该 对 象 的 指 针 引 用 类 型 在 运 行 时 进 行 选 择 的 动 态 联 编 只 能 通 过 指 针 或 引 用 标 示 对 象 来 操 作 虚 函 数 如 果 采 用 一 般 类 型 的 标 示 对 象 来 操 作 虚 函 数, 则 采 用 静 态 联 编 方 式 调 用 虚 函 数 纯 虚 函 数 一 些 类 表 示 没 有 具 体 意 义 的 抽 象 概 念, 它 不 可 能 为 其 虚 函 数 提 供 具 体 的 定 义, 故 可 以 定 义 为 纯 虚 函 数 纯 虚 函 数 只 有 一 个 函 数 声 明, 并 没 有 具 体 函 数 功 能 的 实 现 可 通 过 给 函 数 指 定 零 值 进 行 声 明 纯 虚 函 数 的 定 义 格 式 为 : virtual < 函 数 类 型 >< 虚 函 数 名 称 >(< 参 数 列 表 >)=0 例 如 : virtual void getdata() = 0; 如 果 必 须 使 用 派 生 类 来 创 建 对 象, 每 个 派 生 类 必 须 包 含 每 个 从 基 类 中 继 承 而 来 的 纯 虚 函 数 的 函 数 定 义, 这 样, 确 保 每 次 调 用 都 存 在 可 用 的 函 数 不 能 创 建 含 有 一 个 或 多 个 纯 虚 函 数 的 类 对 象, 因 为 如 果 将 函 数 调 用 发 送 给 纯 虚 函 数 是 不 会 有 任 何 回 应 的 纯 虚 函 数 不 可 以 直 接 调 用, 也 不 可 以 被 继 承 例 10.2 分 析 程 序 执 行 结 果 #include "iostream.h" class A public: virtual void size()=0;
190 ; class B:public A private: double x; public: void size() if(x>=0) cout<<x<<endl; else cout<< x<<endl; B(double xx)x=xx; ; class C:public A private: double x,y; public: void size()cout<<x*x+y*y<<endl; C(double xx,double yy)x=xx;y=yy; ; void main() B b( 9.8); C c(6.0,8.0); b.size(); c.size(); 输 出 结 果 : 第 10 章 虚 函 数 和 多 态 性 抽 象 类 包 含 一 个 或 多 个 纯 虚 函 数 的 类 称 为 抽 象 类 抽 象 类 只 能 作 为 基 类 被 子 类 继 承, 不 能 定 义 抽 象 类 的 对 象, 其 纯 虚 函 数 的 实 现 由 子 类 给 出 如 果 一 个 派 生 类 继 承 了 抽 象 类, 但 是 并 没 有 重 新 定 义 抽 象 类 中 的 纯 虚 函 数, 则 该 派 生 类 仍 然 是 一 个 抽 象 类 只 有 当 派 生 类 中 所 继 承 的 所 有 纯 虚 函 数 都 被 实 现 时, 它 才 不 是 抽 象 类 例 10.3 抽 象 类 举 例
191 182 C++ 程 序 设 计 class Shapes public: virtual void draw() = 0; // 纯 虚 函 数 virtual void rotate(int) = 0; // 纯 虚 函 数 ; class circle: public Shapes private: double radius; public: circle(int r); void draw() void rotate(int) double area()return *radius*radius; double volume()return 3* *radius*radius*radius/4; ; 虽 然 纯 虚 函 数 draw() 和 rotate() 在 子 类 circle 中 的 实 现 语 句 为 空, 但 它 仍 然 是 虚 函 数 在 子 类 中 的 实 现, 所 以 子 类 circle 不 是 一 个 抽 象 类 如 果 类 继 承 了 一 个 没 有 提 供 纯 虚 函 数 定 义 的 抽 象 类, 那 么 它 也 成 为 一 个 抽 象 类, 且 不 能 用 来 定 义 对 象 抽 象 类 的 重 要 用 法 是 提 供 一 个 接 口, 而 不 揭 示 任 何 实 现 的 细 节 10.3 虚 析 构 函 数 在 用 delete 运 算 符 删 除 一 个 对 象 时, 对 于 由 派 生 类 构 造 函 数 分 配 的 内 存 空 间, 不 能 调 用 派 生 类 的 析 构 函 数 来 释 放 它 这 是 因 为 析 构 函 数 是 非 虚 的, 而 且 在 动 态 联 编 下 消 息 将 不 能 到 达 析 构 函 数 在 动 态 联 编 下, 更 好 的 解 决 方 法 是 用 虚 析 构 函 数 来 有 效 地 释 放 内 存 空 间 在 析 构 函 数 前 面 加 上 关 键 字 virtual 进 行 说 明, 称 该 析 构 函 数 为 虚 析 构 函 数 例 如 : class example public: virtual ~example(); ; 例 10.4 分 析 程 序 执 行 结 果 #include "iostream.h" class A private:
192 第 10 章 虚 函 数 和 多 态 性 183 char* a_ptr; public: A () // 构 造 函 数 不 能 是 虚 函 数 a_ptr = new char[5]; virtual void fun()=0; // 虚 成 员 函 数 virtual ~A () // 虚 析 构 函 数 delete[] a_ptr; cout<<" 释 放 A ()"<<endl; ; class B: public A private: char* ptrderived; public: B () ptrderived = new char[100]; ~B () delete[] ptrderived; cout<<" 释 放 B ()"<<endl; void fun() ; void main() A *ptr = new B; delete ptr; 程 序 的 执 行 结 果 为 : 释 放 B () 释 放 A () 如 果 类 A 中 的 析 构 函 数 不 用 虚 函 数, 则 输 出 结 果 为 : 释 放 A ()
193 184 C++ 程 序 设 计 由 上 例 可 以 看 出, 在 基 类 中 有 一 个 虚 析 构 函 数, 当 delete ptr 时, 所 调 用 的 析 构 函 数 是 一 个 与 对 象 *ptr 类 型 相 对 应 的 析 构 函 数, 而 不 是 和 指 针 类 型 相 对 应 的 析 构 函 数 由 于 派 生 类 对 象 总 是 包 含 基 类 对 象, 为 了 确 保 释 放 堆 栈 中 的 所 有 空 间, 必 须 调 用 这 两 个 类 的 析 构 函 数 如 果 一 个 基 类 的 析 构 函 数 被 说 明 为 虚 析 构 函 数, 则 它 的 派 生 类 中 的 析 构 函 数 也 是 虚 析 构 函 数, 不 管 它 是 否 使 用 了 关 键 字 virtual 进 行 说 明 10.4 多 态 多 态 的 含 义 多 态 是 通 过 类 的 继 承, 使 得 同 一 个 函 数 可 以 根 据 调 用 它 的 对 象 类 型 不 同, 作 出 不 同 的 反 应, 这 意 味 着 通 过 带 有 相 同 消 息 的 函 数 执 行 不 同 的 过 程 多 态 是 面 向 对 象 的 重 要 特 性 之 一 多 态 是 通 过 虚 函 数 来 实 现 的 虚 函 数 的 使 用 本 质 是 将 派 生 类 类 型 的 指 针 赋 给 基 类 类 型 的 指 针, 虚 函 数 被 调 用 时 会 自 动 判 断 调 用 对 象 的 类 型, 从 而 作 出 相 应 的 响 应 例 10.5 分 析 下 面 的 程 序 #include "iostream.h" class Shapes public: virtual void draw() // 基 类 中 的 函 数 cout<<"draw Base\n"; virtual double area() return 0; ; class Circle: public Shapes private: int radius; public: void draw() // 在 派 生 类 中 重 新 定 义 cout<<"draw circle"; void area()
194 第 10 章 虚 函 数 和 多 态 性 185 return *radius*radius; ; class Square: public Shapes private: int length; public: void draw() // 在 派 生 类 中 重 新 定 义 cout<<"draw square"; void area() return length* length; ; void main() Circle c; Square s; Shapes* ptr; ptr = &c; ptr >draw(); cout<< "Circle area :"<<ptr >area()<<endl; ptr = &s; ptr >draw(); cout<< "Square area :"<<ptr >area()<<endl; 在 上 例 中,Circle 类 型 的 对 象 和 Square 类 型 的 对 象 分 别 赋 值 给 Shapes 类 型 的 指 针 ptr, 但 ptr >draw() 和 ptr >area() 两 次 出 现 的 执 行 结 果 并 不 同, 第 一 次 执 行 的 是 Circle 类 中 的 成 员 函 数, 第 二 次 执 行 的 是 Square 类 中 的 成 员 函 数 多 态 的 应 用 下 面 通 过 一 个 例 子 来 说 明 多 态 的 应 用 例 10.6 分 析 程 序 执 行 结 果 设 计 学 生 类 student, 提 供 成 员 函 数 kind 表 示 不 同 类 型 的 学 生, 定 义 为 纯 虚 函 数 ; 派 生 A 类 学 生 student_a, 提 供 成 员 函 数 kind 表 示 A 类 学 生, 派 生 B 类 学 生 student_b, 提 供 成 员 函 数 kind 表 示 B 类 学 生 类 student_a 和 类 student_b 都 继 承 学 生 类 #include "iostream.h"
195 186 C++ 程 序 设 计 class student public: virtual void kind()=0; // 定 义 student 类, 成 员 函 数 kind() 为 纯 虚 函 数 ; class student_a:public student // 定 义 类 student_a 继 承 类 student public: void kind(); // 类 student_a 包 含 成 员 函 数 kind() ; class student_b:public student // 定 义 类 student_b 继 承 类 student public: void kind(); // 类 student_b 包 含 成 员 函 数 kind() ; void student_a::kind() // 编 写 类 student_a 和 类 student_b 的 成 员 函 数 kind() cout<<"a 类 的 学 生!"<<endl; void student_b::kind() cout<<"b 类 的 学 生!"<<endl; void kind(student *S) S >kind(); void main() student_a a1; a1.kind(); student_b b1; b1.kind(); cout<<" "; cout<<endl; student *p; p=&a1; kind(p); p=&b1;
196 第 10 章 虚 函 数 和 多 态 性 187 kind(p); 程 序 的 执 行 结 果 如 下 : A 类 的 学 生! B 类 的 学 生! A 类 的 学 生! B 类 的 学 生! 比 较 结 果 可 知, 结 果 是 一 样 的 这 是 因 为 在 执 行 程 序 的 时 候 确 定 调 用 哪 个 类 的 成 员 函 数 kind() 如 果 类 student 又 有 一 个 新 的 继 承 子 类, 函 数 kind() 也 不 需 要 更 改, 只 要 新 的 继 承 子 类 的 kind() 函 数 存 在, 系 统 就 可 以 区 别 调 用 该 子 类 的 kind() 函 数 习 题 1. 为 什 么 要 引 入 虚 函 数 的 概 念? 写 出 定 义 虚 函 数 的 方 法 2. 定 义 虚 函 数 要 遵 循 的 规 则 是 什 么? 3. 怎 么 定 义 纯 虚 函 数? 纯 虚 函 数 有 什 么 特 点? 4. 什 么 是 抽 象 类? 它 有 什 么 作 用? 5. 怎 样 理 解 多 态? 使 用 多 态 有 什 么 好 处? 它 通 过 什 么 实 现? 6. 写 出 下 列 程 序 的 执 行 结 果 #include"iostream.h" class A public: A() cout<<endl<<" 实 例 化 类 A 的 一 个 对 象 "; virtual ~A() cout<<endl<<" 消 除 类 A 的 一 个 对 象 "; virtual void f() cout<<endl<<" 执 行 类 A 的 成 员 函 数 "; ; class B:public A
197 188 C++ 程 序 设 计 public: B() cout<<endl<<" 事 例 化 类 B 的 一 个 对 象 "; virtual ~B() cout<<endl<<" 消 除 类 B 的 一 个 对 象 "; void f() cout<<endl<<" 执 行 类 B 的 成 员 函 数 "; ; void main() A a=a(); B b=b(); cout<<endl<<" "; a.f(); b.f(); cout<<endl<<" "; A *p; p=&b; p >f(); cout<<endl<<" "; 7. 生 成 容 器 类 RQ, 提 供 成 员 函 数 caltj() 计 算 容 器 的 体 积, 定 义 caltj() 为 纯 虚 数, 生 成 LFT 类 表 示 立 方 体, 数 据 成 员 A 表 示 立 方 体 的 边 长, 提 供 成 员 函 数 caltj() 计 算 立 方 体 的 体 积 ; 生 成 长 方 体 类 CFT, 数 据 成 员 A,B,C 分 别 表 示 长 方 体 的 长 宽 高, 提 供 成 员 函 数 caltj() 计 算 长 方 体 的 体 积, 类 CFT 和 类 LFT 都 继 承 类 RQ 8. 下 面 是 一 道 关 于 虚 析 构 函 数 的 程 序 分 析 题, 请 写 出 它 的 执 行 结 果 #include"iostream.h" class shape public: shape(); virtual ~shape()
198 第 10 章 虚 函 数 和 多 态 性 189 cout<<"execting shape dtor"<<endl; ; class Circle:public shape public: Circle(); ~Circle() cout<<"execting Circle dtor"<<endl; ; void main() shape *pshape=new Circle; delete pshape; 9. 按 下 列 要 求 编 程 在 一 个 公 司 里, 主 管 和 员 工 的 月 工 资 计 算 方 法 规 定 如 下 : 主 管 的 每 月 工 资 固 定 为 4200 元 ; 员 工 的 每 月 工 资 与 加 班 的 时 间 有 关, 计 算 方 法 是 每 加 班 一 小 时 50 元, 固 定 工 资 为 2500 元 编 程 实 现 每 个 人 的 月 工 资, 要 求 利 用 纯 虚 函 数 实 现
199 第 11 章 C++ 输 入 / 输 出 流 数 据 的 输 入 / 输 出 是 十 分 重 要 的 操 作, 如 从 键 盘 输 入 数 据, 在 显 示 屏 上 显 示 程 序 的 运 行 结 果, 把 重 要 数 据 保 存 在 数 据 文 件 中 等 但 是 C++ 语 言 没 有 提 供 专 门 的 输 入 / 输 出 语 句, 它 是 通 过 输 入 / 输 出 流 ( 简 称 I/O 流 ) 来 实 现 输 入 / 输 出 操 作 的 I/O 流 不 是 C++ 语 言 的 一 部 分, 而 是 C++ 库 的 一 部 分, 是 C++ 类 的 一 个 集 合 11.1 输 入 / 输 出 流 的 概 念 编 写 一 个 程 序, 无 论 其 目 的 如 何, 总 要 从 文 件 或 设 备 中 读 写 数 据, 这 一 过 程 称 为 输 入 / 输 出 ( 简 写 为 I/O) 操 作 C 语 言 中 没 有 提 供 专 门 的 输 入 / 输 出 语 句,I/O 操 作 利 用 函 数 来 实 现 同 样, C++ 语 言 中 也 没 有 专 门 的 I/O 操 作 语 句,C++ 中 的 I/O 操 作 是 通 过 一 组 标 准 I/O 函 数 或 I/O 流 来 实 现 的 流 (stream) 来 源 于 这 样 的 概 念, 即 数 据 是 从 一 个 位 置 流 向 另 一 个 位 置, 就 如 同 水 从 一 处 流 动 到 另 一 处 在 C++ 程 序 中, 数 据 可 以 从 程 序 流 向 屏 幕 或 磁 盘 文 件, 也 可 以 从 键 盘 或 磁 盘 文 件 流 入 到 程 序 中 C++ 从 C 语 言 接 受 了 一 套 I/O 函 数, 又 提 供 了 一 套 安 全 简 洁 并 且 可 扩 展 的 高 效 I/O 流 系 统 C++ 的 I/O 流 不 仅 拥 有 标 准 I/O 函 数 的 功 能, 而 且 比 标 准 I/O 函 数 功 能 更 强 更 方 便 而 且 更 可 靠 在 C++ 语 言 中, 数 据 的 输 入 和 输 出 操 作 包 括 以 下 几 种 情 况 (1) 对 标 准 输 入 设 备 ( 键 盘 ) 或 标 准 输 出 设 备 ( 显 示 器 ) 进 行 输 入 / 输 出 操 作, 简 称 为 标 准 I/O 流 (2) 对 外 存 ( 如 磁 盘 ) 上 的 文 件 进 行 输 入 / 输 出 操 作, 简 称 为 文 件 I/O (3) 对 内 存 中 指 定 的 字 符 串 存 储 空 间 进 行 输 入 / 输 出 操 作, 简 称 为 串 I/O 简 单 地 讲,I/O 流 是 一 系 列 写 到 屏 幕 显 示 器 上 或 从 键 盘 上 读 出 的 各 种 字 符 当 在 C++ 中 执 行 标 准 的 输 入 / 输 出 操 作 时, 一 般 使 用 I/O 流 cin 作 为 输 入, 使 用 cout 作 为 输 出 事 实 上,C++ 将 I/O 流 定 义 为 类, 输 入 和 输 出 操 作 分 别 由 输 入 流 istream 和 输 出 流 ostream 两 个 类 提 供 而 iostream 是 这 两 个 类 的 派 生 类, 允 许 进 行 双 向 的 I/O 操 作 ostream 的 输 出 操 作 可 认 为 是 一 个 插 入 过 程, 由 左 移 符 ( 或 称 作 插 入 操 作 符 ) << 实 现, 可 以 认 为 数 据 是 被 插 入 到 输 出 流 中 而 istream 的 输 入 操 作 则 可 认 为 是 一 个 提 取 过 程, 由 右 移 符 ( 或 称 作 提 取 操 作 符 ) >> 的 操 作 符 实 现 可 以 认 为 两 个 操 作 符 的 指 示 方 向 就 表 示 数 据 的 移 动 方 向 例 如,cin>>data 语 句 表 示 从 标 准 输 入 ( 键 盘 ) 中 将 数 据 移 入 data 中, 而 cout<<data 语 句 表 示 由 data 中 取 出 数 据 输 出 到 标 准 输 出 ( 显 示 器 ) 中
200 第 11 章 C++ 输 入 / 输 出 流 191 任 何 一 个 使 用 iostream 库 的 程 序 都 必 须 包 含 头 文 件 iostream.h 使 用 流 的 优 点 就 是 它 能 够 处 理 程 序 员 所 常 见 的 每 一 个 类 例 如, 用 户 巳 经 有 了 一 个 名 为 CParty 的 类 且 创 建 了 一 个 名 为 Today_Party 的 实 例, 就 可 以 使 用 标 准 的 流 把 Today_Party 输 出 到 屏 幕 上, 如 下 所 示 : cout<<today_party<<endl; 所 以, 不 必 重 写 一 个 像 PrintParty(CParty $Party0bject) 的 新 函 数 通 过 继 承 和 操 作 符 重 载, 完 全 可 以 使 C++ 相 信 新 的 XParty 类 型 与 其 他 类 型 相 似 因 此 在 做 了 必 要 的 继 承 和 重 载 之 后, 新 的 类 型 能 够 用 标 准 的 C++ 表 示 法 进 行 所 有 的 输 入 / 输 出 操 作 在 C++ 语 言 中, 有 4 个 已 预 先 定 义 好 的 流 对 象, 以 便 用 户 直 接 使 用 (1)cin: 一 个 istream 类 的 对 象, 用 于 处 理 标 准 输 入 (2)cout: 一 个 ostream 类 的 对 象, 用 于 处 理 标 准 输 出 (3)cerr: 一 个 ostream 类 的 对 象, 用 于 处 理 标 准 出 错 信 息, 并 提 供 不 带 缓 冲 区 的 输 出 (4)clog: 一 个 ostream 类 的 对 象, 也 用 于 处 理 标 准 出 错 信 息, 但 提 供 带 有 缓 冲 区 的 输 出 11.2 输 出 流 基 本 输 出 操 作 1. 理 解 cout cout 是 console output 的 缩 写, 意 为 控 制 台 输 出, 表 示 把 程 序 结 果 输 出 到 屏 幕 ( 标 准 输 出 设 备 ) 由 于 cout 是 C++ 预 先 定 义 好 的 4 个 流 对 象 之 一, 故 可 以 直 接 处 理 所 有 C++ 中 预 定 义 的 数 据 类 型 使 用 插 入 操 作 符 (<<) 能 够 将 数 据 输 送 到 输 出 流 中, 最 常 用 的 输 出 是 在 屏 幕 上 显 示 信 息 例 11.1 cout 应 用 举 例 1 #include "iostream.h" void main(void) cout<<"c++ is very easy! "<<endl; 运 行 程 序, 会 在 显 示 器 上 输 出 显 示 如 下 信 息 : C++ is very easy! 插 入 操 作 符 (<<) 可 以 串 联 起 来 使 用, 将 多 个 数 据 项 一 起 输 出 例 11.2 cout 应 用 举 例 2 #include "iostream.h" void main(void) char name[]="zhang San"; int age=25; cout<<"output the name and age:"<<name<<" "<<age<<endl;
201 192 C++ 程 序 设 计 运 行 程 序, 输 出 结 果 为 : Output the name and age:zhang San 25 C++ 中 已 预 先 定 义 好 一 组 插 入 操 作 符, 能 处 理 所 有 标 准 C++ 类 型, 如 char,short,long, char*,float,double,long double 和 void* 本 章 后 面 部 分 将 讨 论 如 何 扩 展 这 一 操 作 符 集, 使 其 可 以 处 理 类 参 数 endl 是 行 结 束 标 记, 使 输 出 流 移 到 下 一 行 首, 它 是 C++ 中 定 义 的 控 制 流 的 操 作 器, 在 格 式 输 出 控 制 一 节 有 专 门 描 述 可 以 将 endl 放 在 任 何 地 方 例 11.3 endl 应 用 举 例 #include "iostream.h" #include "string.h" void main(void) cout<<"the word and their length: "<<endl; cout<<"teacher\t"<< strlen("teacher")<<endl<<"student\t" <<strlen("student")<<endl; cout<<"family\t"<<strlen("family")<<endl; 运 行 程 序, 在 终 端 上 显 示 如 下 信 息 : The word and their length: teacher 7 student 7 family 6 上 面 程 序 中,cout 依 次 将 插 入 操 作 符 (<<) 后 面 的 字 符 串 和 函 数 值 按 给 定 的 格 式 输 出 到 屏 幕 上 \t 是 水 平 制 表 符 实 际 上, 插 入 操 作 符 (<<) 后 面 可 以 使 用 复 杂 的 表 达 式, 系 统 将 自 动 计 算 表 达 式 的 值 并 传 给 插 入 操 作 符 (<<) 在 默 认 的 情 况 下, 指 针 的 值 ( 地 址 ) 是 按 十 六 进 制 的 形 式 显 示 的 例 11.4 以 十 六 进 制 形 式 输 出 显 示 结 果 #include "iostream.h" void main(void) float x=888.; float* p=&x; cout<<"x:\t"<<x<<"\t&x:\t"<<&x<<endl; cout<<"*p:\t"<<*p<<"\tp:\t"<<p<<endl; cout<<"&p:\t"<<&p<<endl; 运 行 程 序, 输 出 结 果 为 : x: 888 &x: 0x0012FF7C
202 第 11 章 C++ 输 入 / 输 出 流 193 *p: 888 p: 0x0012FF7C &p: 0x0012FF78 用 户 用 不 同 的 计 算 机 实 验 上 面 这 个 程 序 时, 得 到 的 &x,p 和 &p 值 与 上 面 给 出 的 结 果 可 能 不 同, 这 是 由 于 计 算 机 内 存 地 址 不 同 造 成 的 如 果 想 要 以 十 进 制 的 形 式 显 示 地 址, 必 须 用 long 类 型 符 进 行 类 型 转 换 将 例 11.4 中 的 3 条 输 出 语 句 变 成 下 述 形 式 : cout<<"x:\t"<<x<<"\t&x:\t"<<long(&x)<<endl; cout<<"*p:\t"<<*p<<"\tp:\t"<<long(p)<<endl; cout<<"&p:\t"<<long(&p)<<endl; 则 屏 幕 输 出 结 果 为 : x: 888 &x: *p: 888 p: &p: 常 见 错 误 初 学 者 比 较 容 易 犯 的 一 个 错 误 是 对 字 符 串 的 操 作 例 如, 运 行 下 面 的 程 序 : #include "iostream.h" void main(void) char str[]="greenhand"; int a[]=100,20; cout<<"output the address of a: "<<a<<endl; cout<<"output the address of str: "<<str<<endl; 该 程 序 的 本 意 是 输 出 a 和 str 的 地 址, 出 乎 意 料 的 是 输 出 如 下 结 果 : Output the address of a: 0x0012ff6c Output the address of str: greenhand 输 出 了 a 的 地 址, 并 没 有 输 出 str 的 地 址 出 现 这 个 问 题 的 原 因 是,str 实 际 上 并 不 表 示 地 址, 而 是 指 向 字 符 数 组 greenhand 的 第 一 个 字 母, 相 当 于 字 符 数 组 的 指 针, 输 出 的 结 果 当 然 是 字 符 串 了 为 了 能 输 出 str 的 地 址 值, 需 要 使 用 强 制 的 类 型 转 换 或 加 入 取 地 址 符 & 来 处 理 下 面 两 条 语 句 都 可 得 到 str 的 地 址 : cout<<"output the address of str: "<<&str<<endl; cout<<"output the address of str: "<<(void*)str<<endl; 输 出 结 果 为 : Output the address of str: 0x0012ff74 3. 输 出 成 员 函 数 输 出 流 ostream 中 包 含 了 很 多 成 员 函 数, 此 处 讨 论 字 符 和 内 存 块 写 入 输 出 流 对 象 的 成 员 函 数 put 和 write, 其 他 成 员 函 数 在 下 节 讨 论 (1)put() 函 数 成 员 函 数 put() 把 单 个 字 符 写 入 输 出 流 中
203 194 C++ 程 序 设 计 例 11.5 用 输 出 成 员 函 数 在 屏 幕 上 输 出 一 串 字 符 Hello! #include "iostream.h" void main(void) cout.put('h'); cout.put('e'); cout.put('l'); cout.put('l'); cout.put('o'); cout.put('!'); cout.put('\n'); 实 际 上, 下 面 两 条 语 句 是 等 价 的 : cout<<'a'; cout.put('a'); 两 者 都 在 屏 幕 上 输 出 一 个 字 符 a (2)write() 函 数 成 员 函 数 write() 输 出 一 串 字 符 该 成 员 函 数 一 般 形 式 为 : write(char* pch, int ncount) 其 中,pch 是 指 向 字 符 数 组 的 指 针,nCount 指 明 从 第 一 个 参 数 中 复 制 输 出 字 符 的 个 数 例 11.6 write() 函 数 应 用 举 例 #include "iostream.h" void main(void) char str[]="you will be the C++ master!"; cout.write(str,sizeof(str) 1); cout<<endl; cout.write(&str[4],4) <<endl; 运 行 程 序, 输 出 结 果 为 : You will be the C++ master! will write() 函 数 在 处 理 二 进 制 流 输 出 时 很 有 用, 在 第 12 章 关 于 文 件 处 理 中 还 将 深 入 讨 论 此 函 数 需 要 说 明 的 是,put() 和 write() 成 员 函 数 都 返 回 一 个 对 流 对 象 的 引 用, 这 里 给 出 的 例 子 中 都 忽 略 了 返 回 值, 通 常 使 用 这 个 返 回 值 来 测 试 错 误 状 态 除 此 之 外, 调 用 成 员 函 数 good() 和 bad() 来 检 测 输 出 流 错 误, 如 果 不 存 在 错 误, 则 good() 返 回 一 个 非 零 的 整 数 值 ; 若 出 现 错 误, 则 bad() 返 回 非 零 整 数 值 4. 重 载 插 入 操 作 符 为 了 使 插 入 操 作 符 (<<) 能 处 理 除 char,short,long,char*,float,double,long double
204 第 11 章 C++ 输 入 / 输 出 流 195 和 void* 以 外 的 其 他 类 型 变 量, 需 要 重 载 插 入 操 作 符 (<<) 实 质 上 是 指 定 两 个 数 据 类 型, 并 要 求 C++ 编 译 器 为 它 们 根 据 数 据 类 型 区 别 对 待 假 设 有 一 个 名 为 CDate 的 类, 存 储 有 关 时 间 的 数 据, 现 在 要 将 这 些 数 据 输 出 到 屏 幕 上 如 果 用 传 统 的 编 程 方 式, 需 要 编 写 一 个 专 门 用 于 显 示 时 间 信 息 的 成 员 函 数 show_date 来 显 示 时 间 信 息 例 11.7 使 用 成 员 函 数 show_date 显 示 CDate 类 的 时 间 信 息 #include "iostream.h" #include "string.h" class Cdate public: CDate(char *Year,char *Month, char *Date, char* Time); void show_date(void); private: char Year[32]; char Month[32]; char Date[32]; char Time[32]; ; CDate::CDate(char *Year, char *Month, char *Date, char *Time) strcpy(cdate::year, Year); strcpy(cdate::month, Month); strcpy(cdate::date, Date); strcpy(cdate::time, Time); void CDate::show_date(void) cout<<"year:\t"<<year<<endl; cout<<"month:\t"<<month<<endl; cout<<"date:\t"<<date<<endl; cout<<"time:\t"<<time<<endl; void main(void) CDate current_date("2004 年 ","2 月 ","14 日 ","19 时 25 分 "); current_date.show_date(); 显 然 以 调 用 成 员 函 数 的 方 式 来 显 示 类 的 内 容 不 够 直 观, 所 以 希 望 用 cout<< 形 式 来 显 示 类
205 196 C++ 程 序 设 计 可 以 通 过 为 CDate 对 象 重 载 插 入 操 作 符 (<<) 来 省 略 类 CDate 的 成 员 函 数 show_date 这 样 程 序 就 可 以 使 用 插 入 操 作 符 (<<) 来 显 示 有 关 当 前 日 期 的 信 息, 实 现 用 标 准 的 输 出 流 把 CDate 输 出 到 屏 幕 上 如 下 所 示 : cout<<current_date; 为 了 重 载 插 入 操 作 符 (<<), 程 序 必 须 定 义 一 个 在 每 次 对 类 使 用 操 作 符 时 执 行 的 函 数 下 面 语 句 实 现 重 载 : friend ostream& operator <<(ostream &stream, CDate Dateinfo); 重 载 插 入 操 作 符 (<<) 时, 指 定 了 一 个 当 遇 到 该 操 作 符 时 由 程 序 执 行 的 函 数 本 例 中, 这 个 函 数 返 回 了 一 个 ostream 对 象 的 参 考 (&) 该 操 作 符 的 参 数 是 一 个 ostream 对 象 和 一 个 CDate 对 象 插 入 操 作 符 (<<) 左 侧 和 右 侧 的 值 :cout 是 ostream 对 象,current_date 是 CDate 对 象 重 载 插 入 操 作 符 (<<) 后 把 各 个 域 插 入 到 输 出 流 之 中 后, 使 用 return 语 句 返 回 被 更 新 的 流 : return (stream); 下 面 是 该 程 序 的 完 整 实 现 例 11.8 通 过 重 载 插 入 操 作 符 (<<) 来 显 示 时 间 #include "iostream.h" #include "string.h" class CDate public: CDate(char *Year,char *Month, char *Date, char* Time); friend ostream& operator <<(ostream &stream, CDate Dateinfo); private: char Year[32]; char Month[32]; char Date[32]; char Time[32]; ; CDate::CDate(char *Year, char *Month, char *Date, char *Time) strcpy(cdate::year, Year); strcpy(cdate::month, Month); strcpy(cdate::date, Date); strcpy(cdate::time, Time); ostream &operator<<(ostream &stream, CDate Dateinfo) cout<<"year:\t"<<dateinfo.year<<endl; cout<<"month:\t"<<dateinfo.month<<endl; cout<<"date:\t"<<dateinfo.date<<endl;
206 第 11 章 C++ 输 入 / 输 出 流 197 cout<<"time:\t"<<dateinfo.time<<endl; return(stream); void main(void) CDate current_date("2004 年 ","2 月 ","14 日 ","19 时 25 分 "); cout<<"cdate Information:"<<endl<<current_date; 运 行 程 序, 输 出 结 果 为 : CDate Information: Year: 2004 年 Month: 2 月 Date: 14 日 Time: 19 时 25 分 在 最 后 一 条 语 句 中, 字 符 串 操 作 器 和 类 对 象 同 时 出 现, 互 不 干 扰 输 出 格 式 控 制 前 面 所 讲 的 例 题 程 序 的 输 出 结 果 都 是 无 格 式 的 实 际 上,C++ 流 iostream 包 含 了 丰 富 的 控 制 输 出 格 式 的 技 术 每 个 流 的 格 式 化 信 息 都 由 一 系 列 标 志 位 组 成, 通 过 调 用 操 作 器 或 调 用 成 员 函 数 就 能 够 设 置 这 些 标 志 位 将 操 作 器 放 在 插 入 操 作 符 (<<) 所 在 行 中, 就 可 以 修 改 输 出 操 作 本 书 前 面 的 许 多 例 题 程 序 中 都 使 用 了 标 识 符 endl, 它 就 是 操 作 器 之 一 endl 标 识 符 是 一 个 修 改 输 出 流 格 式 的 操 作 器, 表 示 输 出 行 结 束 总 之, 有 几 种 方 法 可 以 达 到 格 式 化 输 出 的 目 的 : 一 种 是 使 用 操 作 器, 另 一 种 是 设 置 标 志 位, 第 三 种 是 调 用 成 员 函 数 1. 操 作 器 操 作 器 的 使 用 类 似 于 函 数, 使 用 很 简 捷, 只 需 将 操 作 器 与 插 入 操 作 符 (<<) 串 联 使 用 即 可 大 部 分 的 操 作 器 在 iomanip.h 中 定 义, 只 有 少 部 分 在 输 入 / 输 出 流 中 定 义, 所 以 使 用 操 作 器 时 一 般 要 包 含 iomanip.h 头 文 件 (1) 控 制 浮 点 数 显 示 精 度 (setprecision) 用 setprecision(int np) 控 制 浮 点 数 显 示 精 度, 其 中 np 为 浮 点 位 数, 可 用 setprecision 操 作 器 来 控 制 输 出 流 显 示 的 数 据 位 数, 默 认 状 态 下 浮 点 数 的 输 出 精 度 是 6 位 有 效 数 字 如 果 显 示 格 式 为 定 点 形 式, 则 np 表 示 小 数 点 后 的 位 数 例 11.9 setprecision 应 用 举 例 #include "iostream.h" #include "iomanip.h" void main(void) cout<<"float:"<<endl; for(int i=1;i<8;i++)cout<<setprecision(i)<<200./7.<<endl;
207 198 C++ 程 序 设 计 cout<<setiosflags(ios::fixed)<<"fixed:"<<endl; for(i=1;i<8;i++)cout<<setprecision(i)<<200./7.<<endl; 输 出 结 果 为 : float: 3e fixed: setiosflags(ios::fixed) 表 示 用 定 点 数 形 式 显 示 浮 点 数, 在 流 的 格 式 化 标 志 中 解 释 了 如 何 设 置 流 的 格 式 化 标 志 (2) 控 制 输 出 进 制 (dec,oct,hex 和 setbase) dec,oct 和 hex 分 别 用 于 控 制 十 进 制 八 进 制 和 十 六 进 制 输 出 格 式 默 认 状 态 下 的 输 出 流 格 式 是 十 进 制 setbase(int n) 用 于 设 置 不 同 的 基 数, 如 果 取 n 为 10,8 或 16, 则 等 同 于 dec, oct 或 hex 操 作 器 注 意 : 有 的 编 译 器 不 包 含 setbase 操 作 器 例 用 不 同 的 进 制 输 出 200 #include "iostream.h" #include "iomanip.h" void main(void) int num=200; cout<<"default:\t"<<num<<endl<<"decimal:\t"<<num<<endl; cout<<"octal:\t\t"<<oct<<num<<endl; cout<<"hexadecimal:\t"<<hex<<num<<endl; cout<<setbase(16)<< "Hexadecimal:\t"<<num<<endl; 输 出 结 果 为 :
208 第 11 章 C++ 输 入 / 输 出 流 199 Default: 200 Decimal: 200 Octal: 310 Hexadecimal: c8 Hexadecimal: c8 (3) 控 制 值 的 输 出 宽 度 (setw) 前 面 的 程 序 中 使 用 了 空 格 和 水 平 制 表 符 来 帮 助 格 式 化 输 出 除 了 以 这 种 方 式 强 制 控 制 程 序 的 间 隔 方 式 外, 还 可 以 使 用 setw(int nw) 操 作 器 来 确 定 输 出 域 的 宽 度 如 果 一 个 值 所 需 的 字 符 数 比 setw(int nw) 给 定 的 字 符 数 nw 多, 则 该 值 将 使 用 它 所 需 的 所 有 字 符 如 果 一 个 值 所 需 的 字 符 数 少, 则 数 字 前 填 充 空 格 默 认 状 态 下,nw 为 0, 即 不 设 定 带 宽 setw 操 作 器 仅 影 响 下 一 个 数 值 的 输 出, 所 以 setw 要 多 次 使 用, 这 一 点 setw 与 前 面 讨 论 的 dec,oct,hex 和 setbase 不 同 例 setw 应 用 举 例 #include "iostream.h" #include "iomanip.h" void main(void) for(int i=4;i<=8;i++) cout<<setw(i)<<12345<<endl; 输 出 结 果 : (4) 控 制 填 充 字 符 (setfill) setfill(int nfill) 用 来 在 空 白 处 填 充 字 符 nfill 是 ASCII 码 值, 如 setfill(65) 则 填 充 A 也 可 直 接 写 入 字 符, 如 setfill( * ) 则 填 充 * setfill 与 setw 经 常 配 合 使 用 当 一 个 输 出 没 有 达 到 预 定 的 宽 度 是, 多 余 的 位 置 总 是 被 空 格 充 填 用 setfill 可 以 将 空 格 处 充 填 成 其 他 字 符 例 如, 在 上 例 程 序 中, 若 将 循 环 语 句 改 成 : for(int i=4;i<=8;i++) cout<<setw(i)<<setfill( * )<<12345<<endl; 则 输 出 结 果 变 为 : *12345 **12345 ***12345 (5) 其 他 操 作 器 (ends,flush 及 ws) ends: 插 入 空 终 结 符 ( \0 )
209 200 C++ 程 序 设 计 flush: 刷 新 流 ws: 仅 用 于 输 入, 跳 过 空 格 2. 流 的 格 式 化 标 志 可 以 通 过 设 置 流 的 格 式 化 标 志 达 到 格 式 化 输 入 和 输 出 的 目 的 有 两 种 方 法 设 置 流 的 格 式 化 标 志 : 一 种 是 调 用 操 作 器 setiosflags(long lflags) 或 resetiosflags(long lflags), 另 一 种 方 法 是 调 用 成 员 函 数 setf(long lflags) 或 unsetf(long lflags) (1) 使 用 setiosflags 或 resetiosflags 操 作 器 设 置 格 式 操 作 器 setiosflags(long lflags) 用 于 设 置 由 lflags 标 示 的 格 式 化 标 志 表 11-1 给 出 了 格 式 化 标 志 及 其 作 用 格 式 化 标 志 lflags 是 在 类 std::ios 中 定 义 的 枚 举 类 型 量, 因 此 在 使 用 这 些 标 志 位 时 必 须 在 前 面 用 ios:: 作 为 每 个 常 量 的 开 始 可 以 使 用 按 位 或 运 算 构 成 位 屏 蔽 值, 达 到 在 一 个 操 作 中 设 置 多 种 输 出 格 式 的 目 的 有 些 格 式 化 标 志 在 设 置 后 一 直 起 作 用, 如 果 程 序 执 行 很 大 量 的 I/O 操 作, 有 时 需 要 把 不 同 的 设 置 打 开 或 关 闭 若 想 将 一 个 标 志 恢 复 到 它 的 默 认 设 置, 可 用 resetiosflags(long lflags) 来 实 现 表 11-1 ios 格 式 化 标 志 标 志 位 描 述 ios::skipws ios::left ios::right ios::internal ios::dec ios::oct ios::hex ios::showbase ios::showpoint ios::uppercase ios::showpos ios::scientific ios::fixed ios::unitbuf ios::sdio 输 入 时 跳 过 空 字 符, 默 认 为 关 闭 左 对 齐 输 出, 默 认 为 打 开 右 对 齐 输 出, 默 认 为 关 闭 数 据 的 符 号 左 对 齐, 数 据 右 对 齐, 在 符 号 和 值 之 间 填 充 内 容, 默 认 为 关 闭 以 十 进 制 格 式 显 示 整 数 值, 默 认 为 打 开 以 八 进 制 格 式 显 示 整 数 值, 默 认 为 关 闭 以 十 六 进 制 格 式 显 示 整 数 值, 默 认 为 关 闭 输 出 有 基 数 标 志 显 示 的 数 值, 默 认 为 关 闭 浮 点 数 始 终 显 示 小 数 点, 默 认 为 关 闭 十 六 进 制 显 示 A~F, 科 学 计 数 法 表 示 的 值 显 示 E, 默 认 为 关 闭 正 数 前 显 示 +, 默 认 为 关 闭 以 科 学 计 数 法 显 示 浮 点 数, 默 认 为 关 闭 用 定 点 数 形 式 显 示 浮 点 数, 默 认 为 打 开 在 完 成 插 入 操 作 后 立 即 刷 新 流 的 缓 冲 区, 默 认 为 关 闭 在 完 成 插 入 操 作 后 刷 新 系 统 的 stdout 和 stderr 流, 默 认 为 关 闭 例 格 式 化 标 志 的 应 用 举 例 #include "iostream.h" #include "iomanip.h" void main(void) double pie= ,x=3.5; int n=255,m=300;
210 第 11 章 C++ 输 入 / 输 出 流 201 cout<<n<<endl; // 默 认 状 态 下 为 十 进 制 cout<<setiosflags(ios::hex)<<n<<endl; // 十 六 进 制 cout<<setiosflags(ios::hex ios::uppercase) // 十 六 进 制 字 符 大 写 <<n<<endl; cout<<setiosflags(ios::hex ios::uppercase ios::showbase)<<n<<endl; // 十 六 进 制 字 符 大 写 带 基 指 示 符 cout<<setw(6)<<setiosflags(ios::right // 右 对 齐 十 六 进 制 ios::uppercase ios::showbase) // 字 符 大 写 带 基 指 示 符 <<n<<endl; cout<<m<<endl; // 除 左 对 齐 外, 其 他 与 上 条 语 句 输 出 相 同 // 说 明 设 置 的 标 志 位 仍 然 起 作 用 cout<<resetiosflags(ios::hex) // 恢 复 为 十 进 制 <<n<<endl; cout<<pie<<endl; // 默 认 输 出 浮 点 数 cout<<setiosflags(ios::showpos) // 输 出 带 + <<x<<endl; cout<<setiosflags(ios::scientific) // 带 + 科 学 计 数 法 <<x<<endl; cout<<resetiosflags(ios::uppercase) // 恢 复 为 小 写 e, 仍 为 科 学 计 数 法 <<pie<<endl; cout<<setiosflags(ios::fixed) // 带 + 定 点 数 <<x<<endl; cout<<setiosflags(ios::showpoint) // 带 + 定 点 数 带 小 数 点 <<x<<endl; cout<<resetiosflags(ios::showpoint ios::showpos) // 去 除 定 点 和 + <<x<<endl; 输 出 结 果 为 : 255 ff FF 0XFF 0XFF 0X12C E e+000
211 202 C++ 程 序 设 计 (2) 使 用 成 员 函 数 设 置 格 式 设 置 流 格 式 化 标 志 的 第 二 种 方 法 是 调 用 成 员 函 数 setf,unsetf 或 flags setf(long lflags) 函 数 用 来 设 置 格 式 化 标 志,unsetf(long lflags) 函 数 是 恢 复 标 志 位, 这 两 个 函 数 的 功 能 与 setiosflags(long lflags) 和 resetiosflags(long lflags) 两 个 操 作 器 非 常 相 似 但 setf 和 unsetf 是 真 正 的 成 员 函 数, 应 用 上 所 受 限 制 比 操 作 器 要 少 例 如 : cout.setf(ios::scientific ios::showpos); 或 cout.unsetf(ios::scientific ios::showpos); flags(long iflags) 是 重 载 函 数 用 flags(long iflags) 设 置 格 式 化 标 志 时, 用 法 与 setf 相 同 但 flags() 可 以 取 得 当 前 的 格 式 化 标 志 值 如 下 面 语 句 : cout.flags(ios::scientific ios::showpos); cout<<cout.flags()<<endl; 显 示 格 式 化 标 志 值 :+3072 根 据 编 译 器 的 不 同, 此 值 可 能 有 差 别 3. 格 式 化 成 员 函 数 iostream 流 还 包 含 多 个 成 员 函 数 可 供 用 户 格 式 化 输 入 / 输 出, 其 中 一 些 成 员 函 数 与 操 作 器 的 功 能 非 常 相 近 (1) 填 充 和 获 取 字 符 的 成 员 函 数 (fill) fill 是 重 载 函 数, 分 别 为 fill(char nfill) 和 fill() fill(char nfill) 与 操 作 器 setfill 功 能 相 同, 用 于 填 充 字 符 例 如 : cout.fill('a'); 或 cout.fill(100); fill() 用 于 获 取 当 前 的 填 充 字 符 例 如 : cout<<setfill(65); cout<<cout.fill()<<endl; 将 在 屏 幕 上 输 出 字 符 A (2) 设 置 或 获 取 浮 点 精 度 成 员 函 数 (precision) precision 是 重 载 函 数 成 员 函 数 precision(int np) 用 于 设 置 浮 点 值 的 精 度, 功 能 与 操 作 器 setprecision 相 同 成 员 函 数 precision() 用 于 获 取 当 前 精 度 例 如 : cout.precision(3); cout<<cout.precision()<<endl; 将 在 屏 幕 上 输 出 精 度 3 (3) 设 置 或 获 取 域 宽 成 员 函 数 (width) width 是 重 载 函 数 成 员 函 数 width(int nw) 用 于 设 置 域 宽, 功 能 与 操 作 器 setw 相 同 成 员 函 数 width() 用 于 获 取 当 前 域 宽 例 如 :
212 第 11 章 C++ 输 入 / 输 出 流 203 cout.width(8); cout<<cout.width()<<endl; 将 在 屏 幕 上 输 出 结 果 ddddddd 输 入 流 基 本 输 入 操 作 1. 理 解 cin cin 是 console input 的 缩 写, 意 为 控 制 台 输 入, 表 示 从 键 盘 ( 标 准 输 入 设 备 ) 输 入 数 据 由 于 cin 是 C++ 预 先 定 义 好 的 4 个 流 对 象 之 一, 故 可 以 直 接 处 理 所 有 C++ 中 预 定 义 的 数 据 类 型 提 取 操 作 符 (>>) 用 来 处 理 从 一 个 流 的 输 入, 它 从 流 中 得 到 数 据 并 将 该 数 据 送 到 变 量 中 与 插 入 操 作 符 (<<) 一 样, 提 取 操 作 符 (>>) 也 可 以 连 续 书 写 进 行 多 项 输 入 例 cin 应 用 举 例 #include "iostream.h" void main(void) int year,month,day; char ch; cout<<"please input year,month,day: " cin>>year>>month>>day; cout<<"this is the date:\t"<<year<<" "<<month<<" "<<day<<endl; cout<<"please type in characters: "; for(int i=0;i<10;i++) cin>>ch; cout<<ch; 在 进 行 多 项 输 入 时, 从 键 盘 输 入 的 输 入 项 要 用 空 白 符 (whitespace, 包 括 空 格 换 行 符 和 制 表 符 ) 隔 开 对 于 输 入 整 型 浮 点 型 数 据, 空 白 符 只 起 间 隔 作 用, 系 统 会 忽 略 其 值 不 能 用, 作 为 隔 离 符, 否 则 将 不 能 得 到 预 期 结 果 对 于 输 入 字 符, 空 白 符 将 被 忽 略 下 面 是 上 例 的 输 入 及 输 出 结 果 : Please input year,month,day: This is the date: Please type in characters:a b cd e f g h i j k l m n abcdefghi 例 处 理 输 入 的 字 符 串
213 204 C++ 程 序 设 计 #include "iostream.h" #include "string.h" void main(void) char name[15]; cout<<"type in your name please: "; cin>>name; cout<<"the name and it\'s length are: "<<name<<" "<<strlen(name)<<endl; 输 入 一 串 字 符 后, 程 序 会 输 出 刚 刚 输 入 的 字 符 串 并 计 算 字 符 串 的 长 度 但 以 这 种 方 式 输 入 的 字 符 串 中 不 能 含 有 空 白 符, 程 序 遇 到 空 白 符 时 认 为 字 符 串 结 束 如 输 入 John Smith, 程 序 只 接 受 John 这 种 方 式 限 制 了 文 本 的 输 入 如 果 要 输 入 带 空 白 符 的 文 本, 就 要 用 下 面 要 讲 到 的 成 员 函 数 getline 2. 输 入 成 员 函 数 与 输 出 流 类 似, 输 入 流 istream 中 包 含 了 很 多 成 员 函 数 大 多 数 简 单 的 C++ 程 序 用 cin 和 提 取 操 作 符 (>>) 来 执 行 输 入 操 作 但 当 程 序 变 得 复 杂 时, 或 许 需 要 对 输 入 进 行 更 精 细 的 控 制, 从 而 超 出 了 操 作 符 所 能 提 供 的 功 能 范 围 这 时 可 以 用 I/O 流 输 入 成 员 函 数 (1) 从 流 中 获 取 一 个 字 符 ( 串 ) 的 成 员 函 数 (get) get 是 重 载 函 数 成 员 函 数 get(char &ch) 从 输 入 流 获 取 一 个 字 符 并 把 该 字 符 存 入 ch 中, 成 员 函 数 get() 从 输 入 流 中 读 入 一 个 字 符 并 将 该 字 符 的 ASCII 码 值 作 为 函 数 的 返 回 值 get() 经 常 用 于 提 示 用 户 按 ENTER 键 继 续 成 员 函 数 get(char* pch, int ncount, char delim = '\n') 从 输 入 流 中 获 取 字 符, 直 到 换 行 符 或 某 个 特 殊 字 符 delim, 或 遇 到 第 ncount 个 字 符 结 束 输 入, 字 符 串 放 入 pch 中 下 面 的 示 例 程 序 演 示 了 这 三 个 成 员 函 数 提 示 输 入 一 个 Y 或 N 响 应 字 符, 如 果 程 序 从 输 入 流 中 获 取 的 字 符 不 是 Y 或 N, 程 序 一 直 接 收 字 符, 直 到 获 取 Y 或 N, 程 序 才 进 行 下 面 的 工 作 为 了 简 化 程 序, 将 所 有 字 符 转 换 成 大 写 例 成 员 函 数 get 应 用 举 例 #include "iostream.h" #include "ctype.h" void main(void) char ch; char chs[128]; cout<<"please enter to continue:"<<endl; cin.get(); cout<<"please type in characters:"<<endl; cin.get(chs,6,'k'); // 此 处 delim 设 为 'k', 如 输 入 , 则 chs 为 12345, // 如 输 入 12k4567, 则 chs 为 12 cout<<"you\'ve get: "<<chs<<endl;
214 第 11 章 C++ 输 入 / 输 出 流 205 cout<<"please type in Y or N: "; do cin.get(ch); ch=toupper(ch); while(ch!='y'&&ch!='n'); cout<<endl<<"you typed: "<<ch<<endl; (2) 从 流 中 读 取 输 入 行 的 成 员 函 数 (getline) 成 员 函 数 getline(char* pch, int ncount, char delim = '\n') 从 输 入 流 中 读 入 整 行 文 本 存 入 pch, 遇 到 某 个 字 符 delim 或 读 到 第 ncount 个 字 符 时 返 回 该 函 数 最 多 读 入 ncount 1 个 字 符, 换 行 符 不 被 作 为 结 束 输 入 的 特 殊 字 符 可 根 据 需 要 设 置, 令 getline 遇 到 某 个 特 殊 字 符 时 结 束 输 入 操 作 如 果 设 置 了 特 殊 字 符 令 getline 结 束 输 入 操 作, 下 一 个 输 入 操 作 将 从 该 特 殊 字 符 后 面 的 字 符 继 续 开 始 例 成 员 函 数 getline 应 用 举 例 #include "iostream.h" void main(void) char line[10]; cout<<"please type in line of text:"<<endl; cin.getline(line,sizeof(line),'y'); cout<<"first line: "<<line<<endl; cin.getline(line,sizeof(line),'y'); cout<<"last line: "<<line<<endl; 编 译 运 行 上 面 程 序, 尝 试 输 入 不 同 的 字 符 串, 观 察 输 出 结 果 ENTER 也 被 认 为 是 字 符 如 果 输 入 的 字 符 串 中 不 包 含 字 符 y, 程 序 处 于 等 待 输 入 状 态, 直 到 输 入 足 够 的 字 符 如 输 入 的 字 符 串 中 含 y 字 符, 成 员 函 数 getline 结 束, 执 行 下 一 条 语 句 (3) 从 流 中 读 取 字 符 串 的 成 员 函 数 (read) 成 员 函 数 read(char* pch, int ncount) 从 输 入 流 中 读 取 ncount 个 字 符, 当 输 入 流 中 的 字 符 数 小 于 ncount 时, 结 束 读 取 经 常 使 用 read 函 数 读 取 二 进 制 数 据 在 第 12 章 文 件 处 理 中 还 将 深 入 讨 论 此 函 数 例 如 : char ch[10]; cin.read(ch,5); 从 键 盘 输 入 中 读 取 5 个 字 符 放 入 ch 中 (4) 确 定 提 取 字 符 数 成 员 函 数 (gcount) 当 程 序 从 键 盘 提 取 字 符 时, 可 能 需 要 确 切 知 道 提 取 的 字 符 数 为 此 可 使 用 成 员 函 数 gcount() 回 车 被 当 成 字 符 计 算 在 内 例 如, 下 面 的 语 句 显 示 字 符 串 line 的 字 符 数 :
215 206 C++ 程 序 设 计 char line[100]; cin.getline(line,sizeof(line)); cout<<"line has: "<<cin.gcount()<<" characters"<<endl; (5) 忽 略 输 入 流 中 字 符 成 员 函 数 (ignore) 当 程 序 执 行 输 入 操 作 时, 有 时 需 要 忽 略 输 入 流 中 的 一 些 字 符 或 某 个 字 符 之 前 的 字 符 成 员 函 数 ignore(int ncount = 1, int delim = EOF) 略 去 ncount 个 字 符, 默 认 状 态 下 ncount 默 认 为 1 例 成 员 函 数 ignore 应 用 举 例 #include "iostream.h" void main(void) char line[10]; cout<<"please type in line of text: "; cin.ignore(4,'a'); cin.getline(line,sizeof(line)); cout<<"after ignore: "<<line<<endl; 下 面 是 输 入 两 串 字 符 忽 略 后 的 输 出 结 果 : Please type in line of text: after ignore: Please type in line of text: 12a after ignore: (6) 返 退 提 取 字 符 的 成 员 函 数 (putback) 成 员 函 数 putback(char ch) 将 从 流 中 提 取 的 字 符 再 返 退 到 流 中 如 果 返 退 的 字 符 ch 不 是 先 前 从 流 中 提 取 的 字 符, 结 果 不 定 例 成 员 函 数 putback 应 用 举 例 #include "iostream.h" void main() char a,b,c,d; cin>>a>>b>>c>>d; cout<<a<<" "<<b<<" "<<c<<" "<<d<<endl; cin.putback(b); cin>>a>>b>>c>>d; cout<<a<<" "<<b<<" "<<c<<" "<<d<<endl; 先 从 输 入 流 中 分 别 提 取 字 符 a,b,c 和 d, 然 后 将 b 返 退 到 流 当 前 的 位 置, 如 输 入 流 是 , 则 将 2 放 在 5 之 前, 当 前 流 成 为 两 次 读 取 的 a,b,c 和 d 分 别 为 :1,2, 3,4,2,5,6,7 3. 重 载 提 取 操 作 符 (>>)
216 第 11 章 C++ 输 入 / 输 出 流 207 对 提 取 操 作 符 (>>) 的 重 载, 类 似 于 对 插 入 操 作 符 (<<) 的 重 载 下 面 的 例 子 中 先 输 出 类 对 象 Marry_birthday, 然 后 输 入 类 对 象 birthday, 并 按 给 定 格 式 输 出 例 重 载 提 取 操 作 符 (>>) 举 例 #include "iostream.h" #include "string.h" class CDate public: CDate(int Year, int Month, int Day); friend ostream& operator <<(ostream &stream, CDate Date); friend istream& operator >>(istream &stream, CDate *Date); private: int Year; int Month; int Day; ; CDate::CDate(int Year, int Month, int Day) CDate::Year=Year; CDate::Month=Month; CDate::Day=Day; ostream &operator<<(ostream &stream, CDate Date) stream<<date.year<<'/'<<date.month<<'/'<<date.day<<endl; return(stream); istream &operator>>(istream &stream, CDate *Date) stream>>date >Year; stream>>date >Month; stream>>date >Day; return(stream); void main(void) CDate Marry_birthday (2004,1,22); CDate birthday(2004,6,1); cout<<" Marry_birthday is: "<< Marry_birthday;
217 208 C++ 程 序 设 计 cout<<"type in your birthday yyyy mm dd: "; cin>>&birthday; cout<<"your birthday is: "<<birthday<<endl; 上 面 例 子 中, 下 述 语 句 实 现 重 载 : istream &operator>>(istream &stream, CDate *Date) 重 载 提 取 操 作 符 (>>) 时, 指 定 了 一 个 当 遇 到 该 操 作 符 时 由 程 序 执 行 的 函 数 这 个 函 数 返 回 了 一 个 istream 对 象 的 参 考 (&) 该 操 作 符 的 参 数 是 一 个 istream 对 象 和 一 个 CDate 对 象 指 针 提 取 操 作 符 (>>) 左 侧 和 右 侧 的 值 :cin 是 istream 对 象,birthday 是 CDate 对 象 重 载 提 取 操 作 符 (>>) 后 把 各 个 域 插 入 到 输 入 流 中 后, 使 用 return 语 句 返 回 被 更 新 的 流 输 入 格 式 控 制 与 输 出 格 式 控 制 一 样, 通 过 调 用 操 作 器 设 置 标 志 位 和 调 用 成 员 函 数 就 能 够 设 置 这 些 标 志 位 在 需 要 大 量 输 入 数 据 的 情 况 下, 使 用 标 准 输 入 很 不 方 便 且 容 易 出 错, 需 要 使 用 文 件 I/O 所 以 标 准 输 入 中, 用 于 输 入 控 制 的 手 段 较 少 在 输 出 格 式 控 制 一 节 中 讨 论 的 操 作 器 流 的 格 式 化 标 志 和 成 员 函 数, 有 一 少 部 分 可 用 于 输 入 流 格 式 控 制 例 输 入 格 式 控 制 距 离 #include "iostream.h" #include "iomanip.h" void main(void) int i,j,k; cin.setf(ios::hex); cin.fill('*'); cin>>setw(8)>>i>>oct>>j>>dec>>k; cout<<i<<endl; cout<<j<<endl; cout<<k<<endl; cout<<cin.width()<<endl; cout<<cin.fill()<<endl; 分 别 用 十 六 进 制 八 进 制 和 十 进 制 输 入 i,j 和 k, 以 十 进 制 输 出, 设 置 域 宽 为 8, 填 充 字 符 * 习 题 1. 什 么 是 标 准 输 入 / 输 出?C++ 输 入 / 输 出 如 何 实 现? 2. 列 举 几 个 常 用 的 输 入 / 输 出 成 员 函 数 3. 有 哪 几 种 方 式 控 制 输 出 格 式?
218 第 11 章 C++ 输 入 / 输 出 流 什 么 是 操 作 器? 如 何 使 用? 5. 如 何 控 制 浮 点 数 的 输 出 精 度? 6. 怎 样 控 制 输 出 进 制? 7. 怎 样 控 制 流 的 格 式 化 标 志? 8. 如 何 输 出 char* 变 量 的 地 址? 9.C++ 中 的 I/O 操 作 是 通 过 一 组 标 准 或 来 实 现 的 10. 在 C++ 语 言 中, 数 据 的 输 入 和 输 出 包 括 对 标 准 输 入 设 备 和 标 准 输 出 设 备 对 在 外 存 上 的 文 件 以 及 对 内 存 中 指 定 的 存 储 等 进 行 操 作 11. 输 入 和 输 出 操 作 分 别 由 和 两 个 类 提 供 12.C++ 中, 有 4 个 流 对 象 已 预 先 定 义 好, 以 便 用 户 直 接 使 用, 分 别 为 : 和 13. 插 入 操 作 符 是, 流 提 取 操 作 符 是 14. 当 使 用 带 参 数 的 操 作 器 时, 程 序 中 必 须 包 含 头 文 件 15. 成 员 函 数 put() 把 写 入 输 出 流 中 16. 浮 点 数 的 默 认 输 出 精 度 为 17. 设 置 标 志 位 可 使 显 示 的 正 数 前 面 带 有 一 个 加 号 18. 流 操 作 器 和 分 别 指 定 整 数 按 八 进 制 十 六 进 制 和 十 进 制 格 式 显 示 19. 默 认 的 输 出 对 齐 方 式 是 对 齐 20. 操 作 器 控 制 输 出 宽 度 21.setfill(68) 填 充 字 符 22. 输 入 成 员 函 数 getline 读 取 字 符 23. 编 写 一 个 程 序, 实 现 下 列 功 能 (1) 输 出 字 符 串 "This is a simple program: "; (2) 输 入 一 个 整 数, 分 别 用 八 进 制 十 进 制 和 十 六 进 制 字 母 按 大 写 的 格 式 输 出 ; (3) 输 入 一 个 浮 点 数, 设 置 一 个 标 志, 以 科 学 记 数 法 显 示 浮 点 数 (4) 输 出 char* 类 型 变 量 int* 类 型 变 量 和 double* 类 型 变 量 的 地 址 (5) 分 别 用 成 员 函 数 和 操 作 器 实 现 设 置 填 充 字 符 '*' (6) 分 别 用 put() 和 write() 输 出 字 符 和 字 符 串 (7) 获 取 当 前 的 浮 点 精 度 (8) 设 置 域 宽 为 10 (9) 从 输 入 流 中 获 取 一 个 字 符 (10) 从 输 入 流 中 获 取 一 串 字 符, 当 字 符 串 中 含 有 字 时 结 束 输 入 (11) 确 定 上 述 提 取 字 符 的 字 符 数 (12) 输 出 并 删 除 字 符 串 中 的 前 5 个 字 符 (13) 用 成 员 函 数 read 给 char 类 型 数 组 ch 输 入 20 个 字 符 (14) 按 右 对 齐 方 式 以 10 位 域 宽 输 出 abcd
219 第 12 章 文 件 处 理 标 准 输 入 / 输 出 是 以 终 端 为 输 出 对 象, 从 键 盘 输 入 数 据, 将 运 行 结 果 输 出 到 屏 幕 上 显 然, 从 终 端 输 入 输 出 数 据, 虽 然 有 时 很 方 便, 但 不 能 永 久 保 存 输 入 / 输 出 数 据, 这 种 情 况 下 可 以 使 用 外 存 储 器 ( 软 盘 硬 盘 等 ) 来 保 存 数 据 各 种 计 算 机 应 用 系 统 通 常 把 一 些 相 关 信 息 组 织 起 来 保 存 在 外 存 储 器 中, 称 为 文 件, 并 用 文 件 名 加 以 标 识 12.1 文 件 简 介 标 准 输 入 / 输 出 是 以 终 端 为 输 出 对 象, 从 键 盘 输 入 数 据, 将 运 行 结 果 输 出 到 屏 幕 上 显 然 从 终 端 输 入 输 出 数 据, 虽 然 有 时 很 方 便, 但 不 能 永 久 保 存 输 入 / 输 出 的 数 据, 需 要 借 助 其 他 存 储 介 质 保 存 数 据, 这 就 需 要 引 入 文 件 的 概 念 C++ 的 文 件 一 般 指 存 储 在 外 部 介 质 上 的 数 据 集 合 一 批 数 据 是 以 文 件 的 形 式 存 放 在 外 部 介 质 上 的, 操 作 系 统 是 以 文 件 为 单 位 对 数 据 进 行 管 理 的 如 果 想 从 文 件 中 读 取 数 据, 必 须 先 按 文 件 的 路 径 和 文 件 名 找 到 指 定 的 文 件, 然 后 再 从 该 文 件 中 读 取 数 据 如 果 要 将 数 据 输 出 到 文 件 中, 也 必 须 先 建 立 一 个 文 件 或 找 到 已 存 在 的 文 件, 才 能 向 它 输 出 数 据 广 义 上 每 一 个 与 主 机 相 连 的 输 入 / 输 出 设 备 都 可 看 作 是 一 个 文 件 例 如, 终 端 键 盘 是 输 入 文 件, 显 示 屏 和 打 印 机 是 输 出 文 件 这 里 的 外 部 存 储 介 质 一 般 特 指 磁 盘, 磁 盘 上 的 文 件 称 为 磁 盘 文 件 对 磁 盘 文 件 的 输 入 / 输 出 简 称 为 文 件 I/O 使 用 文 件 能 提 高 程 序 的 运 行 效 率 在 程 序 运 行 时, 常 常 需 要 从 文 件 上 读 取 数 据 输 入 到 计 算 机 内 存, 将 程 序 运 行 的 中 间 数 据 或 最 终 结 果 输 出 到 文 件 中 存 放 起 来 每 个 文 件 都 对 应 一 个 文 件 名, 并 且 属 于 某 个 物 理 盘 或 逻 辑 盘 的 目 录 层 次 结 构 中 一 个 确 定 的 目 录 之 下 文 件 名 由 文 件 主 名 和 扩 展 名 两 部 分 组 成, 它 们 之 间 用 圆 点 分 开 文 件 主 名 是 由 用 户 命 名 的 一 个 有 效 的 C++ 标 识 符, 为 了 便 于 记 忆 和 使 用, 一 般 使 文 件 主 名 的 含 义 与 所 存 的 文 件 内 容 相 一 致 在 中 文 Windows 操 作 系 统 中, 可 以 使 用 中 文 长 文 件 名 但 如 果 考 虑 同 其 他 软 件 系 统 兼 容, 文 件 主 名 以 不 超 过 8 个 有 效 字 符 的 标 识 符 为 好 文 件 扩 展 名 是 由 用 户 命 名 的 1~3 个 字 符 组 成, 是 有 效 的 C++ 标 识 符, 通 常 用 它 来 区 分 文 件 的 类 型 如 在 C++ 系 统 中, 用 扩 展 名 h 表 示 头 文 件, 用 扩 展 名 cpp 表 示 源 程 序 文 件, 用 扩 展 名 obj 表 示 程 序 文 件 被 编 译 后 生 成 的 目 标 文 件, 用 扩 展 名 exe 表 示 可 连 接 目 标 文 件 后 形 成 的 可 执 行 文 件 对 于 用 户 建 立 的 用 于 保 存 数 据 的 文 件, 通 常 用 dat 扩 展 名 ; 若 它 是 由 字 符 构 成 的 文 本 文 件, 则 用 txt 作 为 扩 展 名 可 以 根 据 需 要 自 定 义 文 件 扩 展 名 在 C++ 程 序 中 保 存 数 据 的 文 件 按 存 储 格 式 分 为 两 种 类 型, 一 种 为 ASCII 码 文 件 或 文 本 文 件, 它 的 每 一 个 字 节 存 放 一 个 ASCII 代 码, 代 表 一 个 字 符 ; 另 一 种 为 内 部 格 式 文 件 或 二 进 制 文 件,
220 第 12 章 文 件 处 理 211 是 把 内 存 中 的 数 据 按 其 在 内 存 中 的 存 储 形 式 原 样 输 出 到 磁 盘 上 存 放 两 种 存 储 格 式 所 占 用 的 存 储 空 间 不 同 用 ASCII 码 形 式 输 出, 与 字 符 一 一 对 应, 一 个 字 节 代 表 一 个 字 符, 因 而 便 于 对 字 符 进 行 逐 个 处 理, 比 较 直 观, 也 便 于 输 出 字 符 ; 但 一 般 占 存 储 空 间 较 多, 而 且 要 花 费 转 换 时 间 用 二 进 制 形 式 输 出 数 据, 可 以 节 省 外 存 空 间 和 转 换 时 间 ; 但 一 个 字 节 并 不 对 应 一 个 字 符, 不 能 直 接 输 出 字 符 形 式, 不 能 对 输 出 结 果 直 观 观 察 一 般 中 间 结 果 数 据 需 要 暂 时 保 存 在 外 存 上, 以 后 又 需 要 输 入 到 内 存 的 或 外 存 空 间 受 限 制 的, 常 用 二 进 制 文 件 保 存 C++ 语 言 中 没 有 文 件 输 入 / 输 出 语 句, 对 文 件 的 读 写 都 是 用 流 或 C++ 的 库 函 数 来 实 现 的 12.2 文 件 和 流 C++ 语 言 把 文 件 看 作 是 一 个 字 符 ( 字 节 ) 的 序 列, 即 由 一 个 一 个 字 符 ( 字 节 ) 的 数 据 顺 序 组 成 一 个 文 件 是 一 个 字 节 流 或 二 进 制 流 它 把 数 据 看 作 是 一 连 串 的 字 符 ( 字 节 ), 而 不 考 虑 记 录 的 界 限 与 PASCAL 和 FORTRAN 等 高 级 语 言 不 同,C++ 文 件 不 是 由 记 录 组 成 的 输 入 / 输 出 的 字 节 流 或 二 进 制 流 不 受 回 车 换 行 符 等 物 理 符 号 控 制 输 入 时 回 车 换 行 符 作 为 符 号 同 时 被 读 入, 输 出 时 不 会 自 动 增 加 回 车 换 行 符 作 为 标 志 这 种 以 字 节 流 或 二 进 制 流 组 成 的 文 件 被 称 为 流 式 文 件 以 字 符 为 单 位 进 行 操 作 增 加 了 处 理 的 灵 活 性 为 了 进 行 文 件 I/O 操 作,C++ 定 义 了 文 件 流 文 件 流 是 控 制 台 流 的 扩 展, 是 从 控 制 台 流 类 派 生 来 的, 它 继 承 了 控 制 台 流 类 的 所 有 特 点 文 件 流 类 根 据 自 己 的 需 求, 增 加 了 控 制 台 流 类 所 没 有 的 特 性 程 序 为 了 从 文 件 中 读 取 信 息 或 向 文 件 写 入 信 息, 就 必 须 专 门 地 打 开 所 需 的 文 件, 并 且 指 明 文 件 的 属 性 以 确 定 是 想 从 文 件 中 读 还 是 向 文 件 中 写 文 件 流 可 分 为 3 类 : 输 入 文 件 流 ifstream 输 出 文 件 流 ofstream 以 及 输 入 / 输 出 文 件 流 fstream 为 更 好 地 理 解 文 件 流, 可 以 研 究 一 下 头 文 件 fstream.h, 从 中 找 出 ifstream,ofstream 和 fstream 的 类 定 义 和 其 他 高 级 语 言 一 样, 对 文 件 读 写 之 前 应 先 打 开 该 文 件, 在 完 成 操 作 之 后 应 及 时 关 闭 该 文 件 根 据 所 需 执 行 的 文 件 I/O 操 作 类 型, 使 用 文 件 流 创 建 对 象, 然 后 利 用 该 对 象 调 用 相 应 流 中 的 open 成 员 函 数 或 构 造 函 数, 按 照 一 定 的 打 开 方 式 打 开 一 个 文 件 文 件 被 打 开 后, 即 在 流 与 文 件 之 间 建 立 一 个 连 接, 就 可 以 通 过 流 对 象 访 问 它 了, 访 问 结 束 后 再 通 过 流 对 象 关 闭 它 open 的 函 数 原 型 为 : void open( const char* szname, int nmode, int nprot = filebuf::openprot ); 其 中,szName 是 文 件 名, 它 可 包 含 驱 动 器 符 和 路 径 说 明 ;nmode 说 明 文 件 打 开 的 模 式, 它 对 文 件 的 操 作 影 响 重 大, 表 12-1 给 出 了 nmode 的 取 值 范 围 与 其 他 状 态 标 志 一 样,nMode 的 符 号 常 量 可 以 用 按 位 或 运 算 组 合 在 一 起, 如 ios::out ios::app 表 示 添 加 模 式 打 开 输 出 文 件 对 于 ifstream 流,nMode 的 默 认 值 为 ios::in; 对 于 ofstream 流,nMode 的 默 认 值 为 ios::out;nprot 为 文 件 的 访 问 保 护, 一 般 使 用 默 认 值 每 个 文 件 流 中 都 提 供 有 一 个 关 闭 文 件 的 成 员 函 数 close, 当 打 开 的 文 件 操 作 结 束 后, 就 需 要 关 闭 它, 使 文 件 流 与 对 应 的 物 理 文 件 断 开 联 系, 并 能 够 保 证 最 后 输 出 到 文 件 缓 冲 区 中 的 内 容, 无 论 是 否 已 满, 都 将 立 即 写 入 到 对 应 的 物 理 文 件 中 文 件 流 对 应 的 文 件 被 关 闭 后, 还 可 以 利 用 该 文 件 流 调 用 open 成 员 函 数 打 开 其 他 的 文 件
221 212 C++ 程 序 设 计 关 闭 任 何 一 个 流 对 象 所 对 应 的 文 件, 就 是 用 这 个 流 对 象 调 用 close() 成 员 函 数 即 可 表 12-1 流 模 式 标 志 说 明 选 项 描 述 ios::app 添 加 模 式, 所 有 新 数 据 都 写 入 文 件 尾 部 ios::ate 打 开 文 件 时 文 件 指 针 定 位 到 文 件 尾, 如 果 程 序 移 动 了 文 件 指 针, 就 把 数 据 写 入 到 当 前 位 置 ios::in 打 开 文 件 进 行 读 操 作, 文 件 不 存 在 时 出 错 ios::out 打 开 文 件 进 行 写 操 作, 如 文 件 已 存 在 则 更 新 该 文 件 ios::trunc 如 果 文 件 已 存 在 则 清 空 原 文 件 ios::nocreate 打 开 一 个 已 经 存 在 的 文 件, 如 果 文 件 不 存 在 则 打 开 失 败 ios::noreplace 打 开 一 个 不 存 在 的 文 件, 如 果 文 件 存 在 则 打 开 失 败 ios::binary 二 进 制 文 件 ( 非 文 本 文 件 ) 打 开 文 件 操 作 并 不 能 保 证 总 是 正 确 的, 如 文 件 不 存 在 磁 盘 损 坏 等 原 因 可 能 造 成 打 开 文 件 失 败 如 果 打 开 文 件 失 败 后, 程 序 还 继 续 执 行 文 件 的 读 / 写 操 作, 将 会 产 生 严 重 错 误 所 以, 应 首 先 测 试 文 件 打 开 是 否 正 确, 如 不 正 确, 应 使 用 异 常 处 理 以 提 高 程 序 的 可 靠 性 下 列 成 员 函 数 常 用 来 检 验 流 状 态 设 置 流 的 状 态 : int rdstate(); 返 回 流 的 当 前 状 态 标 志 字 int eof(); 返 回 非 0 值 表 示 到 达 文 件 尾 int fail(); 返 回 非 0 值 表 示 操 作 失 败 int bad(); 返 回 非 0 值 表 示 出 现 错 误 int good(); 返 回 非 0 值 表 示 流 操 作 正 常 int clear(int flag=0); 将 流 的 状 态 设 置 为 flag 12.3 顺 序 文 件 的 访 问 文 件 中 有 一 个 位 置 指 针, 指 向 当 前 读 写 位 置 根 据 文 件 打 开 的 模 式, 文 件 被 打 开 后, 不 论 文 件 指 针 置 于 文 件 头 部 或 尾 部, 文 件 指 针 都 是 从 原 位 置 开 始 向 后 移 动, 对 文 件 进 行 读 写 操 作 对 文 件 的 操 作 总 是 从 文 件 指 针 位 置 开 始 顺 序 向 后 移 动, 所 以 称 之 为 顺 序 文 件 建 立 顺 序 访 问 文 件 1. 建 立 文 本 文 件 在 上 一 节 已 经 讨 论 了 建 立 文 件 流 对 象, 用 open 成 员 函 数 或 构 造 函 数 打 开 文 件 下 面 的 语 句 是 以 输 出 方 式 打 开 一 个 文 件 : ofstream outputfile; outputfile.open("d:\\data\\test.dat"); 等 价 于 ofstream outputfile("d:\\data\\test.dat"); 或 fstream outputfile;
222 第 12 章 文 件 处 理 213 outputfile.open("d:\\data\\test.dat",ios::out); 等 价 于 fstream outputfile("d:\\data\\test.dat",ios::out); 第 一 个 参 数 是 要 访 问 的 文 件 名, 可 以 包 含 驱 动 器 符 号 和 路 径 这 样 就 在 指 定 的 目 录 下 创 建 一 个 文 件 如 果 第 一 个 参 数 中 不 包 含 驱 动 器 符 号 和 路 径, 则 在 程 序 所 在 的 目 录 下 创 建 或 打 开 已 有 文 件 文 件 打 开 后, 就 可 以 用 文 件 流 对 象 和 插 入 操 作 符 (<<) 向 文 件 中 写 入 数 据, 其 使 用 方 法 与 标 准 I/O 完 全 类 似 例 如 : outputfile<<"this is the beginning of file I/O"<<endl; 可 根 据 需 要 打 开 不 同 模 式 的 文 件, 例 如 : fstream outputfile; outputfile.open("test.dat",ios::out ios::in); // 输 入 / 输 出 文 件 fstream outputfile; outputfile.open("test.dat",ios::out ios::binary); // 二 进 制 输 出 文 件 fstream outputfile("test.dat",ios::app); // 添 加 方 式 输 出 文 件 实 际 上, 标 准 I/O 中 讨 论 的 操 作 器 设 置 标 志 位 以 及 成 员 函 数 都 可 用 于 文 件 I/O 例 12.1 使 用 操 作 器 设 置 标 志 位 和 成 员 函 数 向 输 出 文 件 中 输 出 文 本 #include "fstream.h" #include "stdlib.h" #include "iomanip.h" void main(void) fstream output; output.open("d:\\data\\test.dat",ios::out); if(output.fail()) cerr<<"can not open test.dat"<<endl; // 打 开 文 件 错 误 时, 给 出 错 误 提 示 abort(); // 终 止 程 序 运 行 output<<setiosflags(ios::left)<<setw(13)<<"name"<<setw(10)<<"class" <<setw(10)<<"age"<<endl; output<<setiosflags(ios::left)<<setw(13)<<"zhang San"<<setw(10)<<10 <<setw(10)<<21<<endl; output<<setiosflags(ios::left)<<setw(13)<<"li Si"<<setw(10)<<10 <<setw(10)<<19<<endl; output<<setiosflags(ios::left)<<setw(13)<<"wang Wu"<<setw(10)<<10 <<setw(10)<<20<<endl; output<<setiosflags(ios::left)<<setw(13)<<"zhao Liu"<<setw(10)<<10 <<setw(10)<<22<<endl;
223 214 C++ 程 序 设 计 for(char ch='a';ch<='z';ch++) output.put(ch); output.write("\n ",11); output.close(); 输 出 到 d:\data\test.dat 文 件 中 的 数 据 为 : Name Class Age Zhang San Li Si Wang Wu Zhao Liu abcdefghijklmnopqrstuvwxyz 如 果 在 D 盘 根 目 录 下 没 有 data 文 件 夹, 则 运 行 程 序 时 会 给 出 Can not open test.dat 的 错 误 提 示, 并 终 止 程 序 运 行 所 以, 例 12.1 需 要 在 D 盘 根 目 录 下 新 建 data 文 件 夹, 或 者 将 语 句 : output.open("d:\\data\\test.dat",ios::out); 改 写 为 : output.open("d:\\test.dat",ios::out); 就 不 会 出 现 错 误 从 上 例 中 可 以 看 出, 输 出 文 件 类 对 象 output 与 标 准 I/O 对 象 cout 很 相 似, 只 是 两 者 的 输 出 指 向 不 同 而 已 2. 建 立 二 进 制 文 件 如 果 程 序 仅 仅 是 为 了 读 写 数 据, 就 没 有 必 要 把 数 据 转 换 成 可 阅 读 的 文 本 格 式 二 进 制 数 据 转 换 成 文 本 格 式 效 率 较 低, 而 以 二 进 制 格 式 读 写 四 字 节 的 浮 点 数 和 两 字 节 的 整 型 数 速 度 是 非 常 快 的 当 程 序 对 文 件 中 数 据 读 写 速 度 要 求 很 高 时, 用 二 进 制 文 件 比 较 合 适 例 如 大 量 读 写 浮 点 数 整 数 或 数 据 结 构 为 执 行 二 进 制 文 件 操 作, 必 须 首 先 使 用 ios::binary 模 式 指 示 符 打 开 文 件 下 面 的 语 句 为 二 进 制 输 出 在 当 前 路 径 中 打 开 名 为 binary_data 的 文 件 : fstream outfile("binary_data.dat",ios::out ios::binary); 应 使 用 read 和 write 成 员 函 数 来 执 行 二 进 制 文 件 的 输 入 / 输 出 操 作, 不 能 使 用 插 入 操 作 符 (<<) 和 提 取 操 作 符 (>>) 向 二 进 制 文 件 中 输 入 / 输 出 数 据, 否 则 可 能 会 遇 到 莫 名 其 妙 的 错 误, 得 不 到 正 确 的 结 果 例 12.2 打 开 一 个 二 进 制 文 件 并 向 其 中 写 入 数 据 #include "stdlib.h" #include "fstream.h" void main(void) fstream output; output.open("d:\\data\\binary_data.dat",ios::out ios::binary); if(!output)
224 第 12 章 文 件 处 理 215 cerr<<"can not open binary_data.dat"<<endl; abort(); double x[]= , , , , ; for(int i=0;i<5;i++) output.write((char*)&x[i],sizeof(double)); //write 成 员 函 数 output.close(); 该 程 序 使 用 了 write 成 员 函 数 write((char*)&x[i],sizeof(double)), 该 函 数 的 第 一 个 参 数 为 指 向 字 符 数 组 的 指 针, 处 理 浮 点 数 时, 要 将 数 据 的 地 址 转 换 成 字 符 指 针 ; 第 二 个 参 数 是 按 字 节 计 算 的 数 据 长 度 读 取 顺 序 文 件 中 的 数 据 为 了 读 取 文 件 中 的 数 据, 程 序 要 创 建 一 个 ifstream 或 fstream 对 象, 就 像 文 件 输 出 需 要 打 开 文 件 一 样, 程 序 可 以 用 open 成 员 函 数 或 构 造 函 数 为 输 出 打 开 文 件 例 如 : ifstream inputfile; inputfile.open("d:\\data\\test.dat"); 等 价 于 ifstream inputfile ("d:\\data\\test.dat"); 或 fstream inputfile; inputfile.open("d:\\data\\test.dat",ios::in); 等 价 于 fstream inputfile ("d:\\data\\test.dat",ios::in); 1. 读 取 文 本 文 件 文 件 被 打 开 后, 程 序 可 以 使 用 插 入 操 作 符 操 作 器 和 成 员 函 数 读 取 文 件 中 的 数 据 程 序 从 文 件 开 始 位 置 读 起, 直 到 遇 到 文 件 结 束 符 为 止 为 确 定 是 否 达 到 了 文 件 结 束 位 置, 程 序 可 以 在 while 循 环 中 使 用 检 验 流 状 态 的 eof 成 员 函 数 例 12.3 读 取 文 件 内 容 到 显 示 器 #include "fstream.h" #include "stdlib.h" void main(void) fstream input("d:\\data\\test.dat",ios::in); if(input.fail()) cerr<<"can not open test.dat"<<endl; abort();
225 216 C++ 程 序 设 计 while(!input.eof()) cout.put((char)input.get()); 此 程 序 将 文 件 d:\\data\\test.dat 中 的 文 本 显 示 到 屏 幕 2. 读 取 二 进 制 文 件 用 read 成 员 函 数 读 取 二 进 制 数 据 和 write 函 数 一 样,read 函 数 的 第 一 个 参 数 为 指 向 字 符 数 组 的 指 针, 第 二 个 参 数 是 从 数 组 中 读 入 的 字 节 数 第 一 个 参 数 也 需 要 char * 型 参 数, 如 果 要 处 理 任 意 类 型 的 参 数, 也 需 要 把 数 据 类 型 转 换 成 char * 型 例 如, 假 设 给 定 的 数 据 为 结 构 体 型 : struct char nation[20]; char name[20]; float height; int age; X; 用 read 成 员 函 数 读 取 X 的 语 句 为 : outfile.read((char*)&x,sizeof(x)); 例 12.4 读 写 二 进 制 文 件 该 程 序 先 打 开 输 入 文 件, 在 文 件 中 输 入 二 进 制 数 据, 关 闭 文 件 然 后 再 打 开 该 文 件, 从 中 读 二 进 制 数 据 并 显 示 在 屏 幕 上 #include "stdlib.h" #include "fstream.h" #include "iomanip.h" void main(void) fstream output; output.open("d:\\data\\binary_data.dat",ios::out ios::binary); if(!output) cerr<<"can not open binary_data.dat"<<endl; abort(); double x[]= , , , , ; for(int i=0;i<5;i++) output.write((char*)&x[i],sizeof(double)); output.close(); fstream input("d:\\data\\binary_data.dat",ios::in ios::binary);
226 第 12 章 文 件 处 理 217 double z[5]; if(input.fail()) cerr<<"can not open binary_data.dat"<<endl; abort(); for(i=0;i<5;i++) input.read((char*)&z[i],sizeof(double)); cout<<setprecision(10)<<z[i]<<endl; input.close(); 运 行 程 序, 输 出 结 果 为 : 更 新 顺 序 文 件 中 的 数 据 对 于 一 个 已 经 存 在 的 文 件, 可 以 用 添 加 的 方 式 修 改 文 件 的 内 容 例 如, 有 一 份 学 生 成 绩 单, 需 要 在 后 面 追 加 一 些 记 录 文 件 打 开 模 式 为 : fstream outapp("d:\\data\\test.dat",ios::app); // 数 据 始 终 输 出 到 文 件 尾 部 fstream outapp("d:\\data\\test.dat",ios::ate); // 数 据 输 出 到 尾 部, 文 件 指 针 可 移 动 fstream outapp("d:\\data\\test.dat",ios::trunc); // 删 除 文 件 中 存 在 的 数 据, 输 出 新 数 据 例 12.5 在 文 件 d:\\data\\test.dat 尾 部 输 出 一 行 字 符 :Liu Ba #include "fstream.h" #include "stdlib.h" #include "iomanip.h" void main(void) fstream output; output.open("d:\\data\\test.dat",ios::app); if(output.fail()) cerr<<"can not open test.dat"<<endl; abort();
227 218 C++ 程 序 设 计 output<<setiosflags(ios::left)<<setw(13)<<"liu Ba"<<setw(10)<<10 <<setw(10)<<18<<endl; output.close(); 使 用 ios::app 模 式 打 开 文 件 时, 如 果 该 文 件 已 存 在, 则 在 文 件 尾 部 输 出 数 据 ; 如 果 文 件 不 存 在, 则 创 建 该 文 件, 然 后 再 输 出 数 据 12.4 随 机 文 件 的 访 问 建 立 随 机 访 问 文 件 顺 序 文 件 的 所 有 操 作 都 是 按 照 从 前 向 后 的 顺 序 进 行 的 实 际 上,C++ 提 供 了 一 种 更 灵 活 的 文 件 读 写 方 式, 通 过 控 制 文 件 指 针 的 定 位, 程 序 可 以 对 文 件 中 某 一 特 定 位 置 进 行 读 写 操 作 就 是 说, 程 序 读 写 完 一 个 数 据 后, 并 不 一 定 要 处 理 下 一 个 数 据, 而 是 通 过 移 动 文 件 指 针, 读 写 文 件 中 其 他 位 置 的 数 据 这 就 是 随 机 访 问 文 件 如 果 同 时 为 读 写 操 作 打 开 文 件, 程 序 就 可 将 读 文 件 指 针 移 到 一 个 位 置, 而 将 写 文 件 指 针 移 向 另 一 个 位 置, 二 者 互 不 干 扰 二 进 制 文 件 的 优 点 之 一 是 大 部 分 数 据 都 是 等 长 的, 例 如 浮 点 数 都 占 4 个 字 节, 整 数 都 占 两 个 字 节,struct 型 的 每 个 实 例 都 是 等 长 的 当 文 件 由 等 长 的 记 录 组 成 时, 文 件 指 针 位 置 就 很 容 易 计 算, 就 可 以 读 取 所 需 要 的 任 何 一 个 数 据, 而 不 必 再 按 顺 序 一 直 读 写 到 所 需 的 数 据 对 于 随 机 文 件, 可 以 按 任 何 顺 序 进 行 读 写 操 作, 所 以, 随 机 文 件 特 别 适 合 于 对 二 进 制 文 件 的 操 作 使 用 seekg 和 seekp 两 个 重 载 成 员 函 数 控 制 文 件 指 针,seekg 用 于 输 入 文 件,seekp 用 于 输 出 文 件 seekg 和 seekp 函 数 的 一 般 格 式 如 下 : seekg(offset,dir); 或 seekg(pos); seekp(offset,dir); 或 seekp(pos); offset 参 数 指 定 了 新 的 位 移 值 ( 以 字 节 为 单 位 ), 为 long 型 dir 指 定 了 文 件 中 读 位 移 量 的 起 始 位 置, 必 须 是 下 列 枚 举 值 之 一 : ios::beg 从 文 件 起 始 位 置 开 始 ios::cur 从 当 前 文 件 指 针 位 置 开 始 ios::end 从 文 件 结 束 位 置 开 始 pos 参 数 指 定 文 件 指 针 的 新 位 置 下 面 是 seekg 和 seekp 成 员 函 数 调 用 的 几 个 例 子 : iuput.seekg(250l,ios::beg); // 将 读 取 文 件 指 针 移 到 离 文 件 开 头 250 个 字 节 处 output.seekp(20l,ios::cur); // 将 写 入 文 件 指 针 移 到 离 文 件 开 头 20 个 字 节 处 input.seekg( 30L,ios::end); // 将 读 取 文 件 指 针 移 到 离 文 件 末 30 个 字 节 处 另 外, 使 用 随 机 文 件 时, 有 时 需 要 确 定 文 件 指 针 的 当 前 位 置 使 用 tellg() 和 tellp() 两 个 成 员 函 数 获 取 文 件 指 针 的 当 前 位 置, 返 回 值 为 从 文 件 起 始 位 置 开 始 到 当 前 位 置 的 字 节 总 数 用 open 成 员 函 数 或 文 件 流 的 构 造 函 数 打 开 文 件, 用 seekg 和 seekp 调 整 文 件 指 针, 就 可 进 行 随 机 文 件 的 存 取
228 第 12 章 文 件 处 理 219 例 12.6 随 机 文 件 的 建 立 和 存 取 假 定 有 10 名 学 生 的 姓 名 学 号 年 龄 性 别 和 总 成 绩 等 数 据, 假 定 需 要 读 取 第 1,3,5,7,9 个 学 生 的 数 据 #include "stdlib.h" #include "fstream.h" struct student_info char name[20]; int num; int age; char sex; double score; ; void main(void) student_info cls1[]= "zhao",1,20,'m',290.5, "qian",2,19,'m',282.5, "sun",3,20,'f',288.5, "li",4,21,'m',275.5, "zhou",5,22,'m',256.5, "wu",6,20,'f',289.5, "zheng",7,19,'m',265.5, "wang",8,20,'f',278.5, "feng",9,21,'f',268.5, "chen",10,20,'f',287.5, ; fstream inout("random.dat",ios::out ios::in ios::binary); if(!inout) cerr<<"can not open random.dat"<<endl; abort(); for(int i=0;i<10;i++) inout.write((char*)&cls1[i],sizeof(cls1[i])); student_info cls2[10]; for(i=0;i<10;i+=2) inout.seekg(i*sizeof(cls1[i]),ios::beg); inout.read((char*)&cls2[i],sizeof(cls2)); cout<<cls2[i].name<<"\t"<<cls2[i].num<<"\t"<<cls2[i].age<<"\t"
229 220 C++ 程 序 设 计 <<cls2[i].sex<<"\t"<<cls2[i].score<<"\t"<<endl; inout.close(); 运 行 程 序, 输 出 结 果 为 : zhao 1 20 M 290.5, sun 3 20 F 288.5, zhou 5 22 M 256.5, zheng 7 19 M 265.5, feng 9 21 F 268.5, 读 取 随 机 文 件 中 的 数 据 处 理 随 机 文 件 时, 文 件 的 定 位 是 关 键 对 于 等 长 的 数 据, 只 要 定 位 准 确, 就 可 自 如 地 读 取 数 据 例 12.7 在 一 个 文 件 中 存 入 一 串 整 型 数 据, 根 据 屏 幕 提 示 输 入 序 号, 显 示 文 件 指 针 的 位 置 和 数 据 #include "stdlib.h" #include "fstream.h" void main(void) fstream inout("random_r.dat",ios::out ios::in ios::binary); if(!inout) cerr<<"can not open random_r.dat"<<endl; abort(); for(int i=0;i<100;i++) inout.write((char*)&i,sizeof(int)); int n,m; cout<<"please type in a number:between 0-99"<<endl; cin>>n; inout.seekg(n*sizeof(int),ios::beg); cout<<"the positon of file pointer after read is: "<<inout.tellg()<<endl; inout.read((char*)&m,sizeof(int)); cout<<"the data you read is: "<<m<<endl; 运 行 程 序, 输 出 结 果 为 : Please type in a number:between ( 注 : 此 数 据 为 用 户 通 过 键 盘 输 入 的, 输 入 完 毕 请 回 车 )
230 The positon of file pointer after read is: 32 The data you read is: 数 据 写 入 随 机 文 件 第 12 章 文 件 处 理 221 对 指 针 进 行 定 位 的 成 员 函 数 seekg 和 seekp 一 般 用 于 二 进 制 文 件, 因 为 文 本 文 件 要 发 生 字 符 转 换, 计 算 位 置 时 往 往 会 发 生 错 乱 处 理 随 机 文 件 时, 一 般 要 求 文 件 的 数 据 类 型 要 一 致, 否 则 定 位 会 出 现 问 题 数 据 写 入 随 机 文 件 时, 首 先 应 用 seekp 定 位, 然 后 用 新 的 数 据 覆 盖 原 来 的 数 据 例 12.8 程 序 先 建 立 一 个 随 机 文 件, 然 后 将 指 定 位 置 的 数 据 用 新 数 据 代 替, 最 后 显 示 写 入 的 数 据 #include "stdlib.h" #include "fstream.h" void main(void) fstream inout("random_w.dat",ios::out ios::in ios::binary); if(!inout) cerr<<"can not open random_w.dat"<<endl; abort(); for(int i=0;i<=10;i++) inout.write((char*)&i,sizeof(int)); cout<<"please input n, 0<=n<=10 "<<endl; int n; cin>>n; inout.seekp(n*sizeof(int),ios::beg); int m=100; inout.write((char*)&m,sizeof(int)); inout.seekg(0,ios::beg); int nd; for(i=0;i<=10;i++) inout.read((char*)&nd,sizeof(int)); cout<<nd<<endl; inout.close(); 程 序 先 建 立 随 机 文 件, 并 向 其 输 出 0~10 共 11 个 整 数, 然 后 从 屏 幕 任 意 输 入 10 以 内 的 数 表 示 位 置, 文 件 中 找 到 该 位 置 并 写 入 新 数 据 100, 最 后 输 出 修 改 以 后 的 文 件
231 222 C++ 程 序 设 计 习 题 1. 什 么 是 C++ 文 件 流?C++ 文 件 操 作 有 什 么 特 点? 2. 对 文 件 的 打 开 与 关 闭 的 含 义 是 什 么? 如 何 打 开 和 关 闭 C++ 文 件? 3. 什 么 是 顺 序 文 件 和 随 机 文 件? 通 过 文 件 指 针 访 问 文 件 有 什 么 好 处? 4. 文 件 打 开 的 模 式 有 哪 些? 它 对 文 件 的 操 作 有 什 么 影 响? 5. 用 于 控 制 文 件 指 针 的 成 员 函 数 有 哪 些, 作 用 是 什 么? 6. 什 么 是 二 进 制 文 件? 有 什 么 特 点? 7. 编 写 一 段 程 序, 从 屏 幕 输 入 一 段 文 字, 在 C 盘 上 建 立 新 文 件 test.dat, 并 把 从 键 盘 输 入 的 文 字 输 出 到 该 文 件 中 8. 编 写 一 段 程 序, 从 键 盘 任 意 输 入 10 个 浮 点 数 并 存 入 二 进 制 文 件 binary 中, 从 此 二 进 制 文 件 中 读 取 该 数 据 并 计 算 其 总 和 和 平 均 值 9. 编 写 一 段 程 序, 从 键 盘 输 入 学 生 姓 名 学 号 和 语 文 数 学 英 语 考 试 成 绩, 计 算 出 总 成 绩, 将 原 有 数 据 和 计 算 出 的 总 成 绩 存 放 在 磁 盘 文 件 result 中 将 result 中 的 数 据 读 出, 按 总 成 绩 排 序 处 理, 并 将 排 序 后 的 数 据 存 入 新 文 件 sort 中 10. 将 上 题 中 sort 文 件 后 补 充 两 个 学 生 的 3 门 课 成 绩, 计 算 总 成 绩 并 重 新 排 序, 输 出 到 新 文 件 中 11. 假 定 一 个 文 件 中 存 有 学 生 的 序 号 姓 名 学 号 年 龄 性 别 及 总 成 绩 等 数 据, 输 出 指 定 序 号 的 学 生 数 据 12. 将 上 题 结 果 仍 存 入 原 有 的 stu sort 文 件 而 不 另 建 立 新 文 件 13. 假 定 文 件 中 存 放 职 工 的 有 关 数 据, 每 个 职 工 的 数 据 包 括 序 号 姓 名 性 别 年 龄 工 种 住 址 工 资 健 康 状 况 文 化 程 度 奖 惩 记 录 和 备 注 等 信 息 要 求 用 读 取 顺 序 文 件 的 方 式 和 读 取 随 机 文 件 的 方 式 屏 幕 输 出 序 号 姓 名 和 工 资 数 据
232 第 13 章 实 训 13.1 实 训 1 熟 悉 Visual C 集 成 开 发 环 境 1. 实 训 目 的 (1) 了 解 Visual C 的 主 要 特 点 (2) 熟 悉 Visual C 的 集 成 开 发 环 境 (3) 学 习 用 Visual C 编 写 简 单 的 C++ 控 制 台 程 序, 掌 握 C++ 程 序 的 上 机 调 试 步 骤 2. 实 训 内 容 使 用 Visual C 集 成 开 发 环 境 编 辑 编 译 和 运 行 下 面 两 个 简 单 的 C++ 程 序 (1)shixun1_1.cpp: #include "iostream.h" void main() cout<<" 欢 迎 大 家 学 习 Visual C++ 6.0"<<endl; (2)shixun1_2.cpp: #include"iostream.h" // 函 数 原 型 int add(int a,int b); int main(int argc, char* argv[]) int x,y,sum; cout<<" 请 输 入 两 个 整 数 :"<<endl; cin>>x>>y; sum=add(x,y); cout<<" 两 数 之 和 为 :"<<sum<<endl; return 0; // 函 数 add 定 义 int add(int a,int b) int c;
233 224 C++ 程 序 设 计 c=a+b; return c; 3. 实 训 操 作 步 骤 (1) 启 动 Visual C 集 成 开 发 环 境 单 击 开 始 / 程 序 菜 单 中 的 Microsoft Visual Studio 6.0 级 联 菜 单 下 的 Microsoft Visual C++ 6.0, 或 双 击 桌 面 上 的 Microsoft Visual C 的 快 捷 方 式, 启 动 Visual C 的 集 成 开 发 环 境, 如 图 13-1 所 示 图 13-1 (2) 创 建 新 工 程 在 文 件 菜 单 下, 选 择 新 建 命 令, 将 弹 出 新 建 对 话 框, 如 图 13-2 所 示 图 13-2
234 第 13 章 实 训 225 单 击 工 程 标 签, 在 该 选 项 卡 中 选 择 Win32 Console Application (Win32 控 制 台 应 用 程 序 ) 选 项, 可 创 建 一 个 基 于 控 制 台 应 用 程 序 的 工 程 在 工 程 编 辑 栏 内 输 入 创 建 的 实 训 名 称 shixun1_1, 在 位 置 编 辑 栏 内 输 入 工 程 欲 保 存 的 路 径, 其 他 选 项 选 择 默 认 值, 单 击 确 定 按 钮 将 弹 出 Win32 Console Application 项 目 步 骤 对 话 框, 如 图 13-3 所 示 图 13-3 在 Win32 Console Application 项 目 步 骤 对 话 框 中 选 择 An empty project 将 创 建 一 个 新 工 程 然 后 单 击 完 成 按 钮, 将 出 现 新 建 工 程 信 息 对 话 框, 如 图 13-4 所 示 图 13-4
235 226 C++ 程 序 设 计 该 对 话 框 给 出 了 新 创 建 工 程 的 简 单 信 息 然 后 单 击 确 定 按 钮, 完 成 一 个 新 工 程 的 创 建 过 程 用 户 也 可 以 在 新 建 对 话 框 中 选 择 文 件 标 签, 出 现 如 图 13-5 所 示 的 对 话 框 图 13-5 在 该 对 话 框 中 选 择 C++ Source File 选 项, 就 可 创 建 一 个 C++ 源 程 序 然 后 在 文 件 编 辑 栏 内 输 入 创 建 的 C++ 源 程 序 名 shixun1_1, 在 目 录 编 辑 栏 内 输 入 C++ 源 程 序 的 保 存 路 径, 单 击 确 定 按 钮 即 可 进 入 代 码 编 辑 窗 口, 如 图 13-6 所 示 图 13-6
236 第 13 章 实 训 227 (3) 编 辑 C++ 源 程 序 文 件 在 右 边 的 程 序 编 辑 窗 口 中 输 入 C++ 源 程 序 shixun1_1.cpp 的 代 码, 如 图 6 所 示 代 码 输 入 完 毕 后, 单 击 文 件 菜 单 中 的 保 存 命 令, 或 直 接 单 击 工 具 栏 上 的 保 存 工 具 按 钮, 保 存 C++ 源 程 序 (4) 编 译 C++ 源 程 序 文 件 单 击 微 型 编 译 工 具 栏 中 的 编 译 程 序 工 具 按 钮, 对 C++ 源 程 序 进 行 编 译 如 果 编 译 有 错 误, 需 要 回 到 程 序 编 辑 窗 口 重 新 编 辑, 直 到 没 有 错 误 为 止 此 时 将 在 信 息 输 出 窗 口 中 显 示 shixun1_1.obj 0 error(s), 0 warning(s) 的 信 息 (5) 编 译 完 成 后, 单 击 微 型 编 译 工 具 栏 中 的 连 接 程 序 工 具 按 钮, 如 果 没 有 连 接 错 误, 将 生 成 可 执 行 文 件 shixun1_1.exe (6) 用 户 可 以 在 Windows 环 境 下 直 接 用 鼠 标 双 击 shixun1_1.exe 文 件, 或 者 单 击 微 型 编 译 工 具 栏 中 的 执 行 程 序 工 具 按 钮, 都 可 以 执 行 程 序 界 面 如 图 13-7 所 示 图 13-7 (7) 按 照 上 述 步 骤, 新 建 编 辑 编 译 并 运 行 shixun1_2.cpp 程 序 程 序 运 行 后, 将 弹 出 一 个 窗 体 要 求 用 户 输 入 两 个 整 数, 用 户 输 入 两 个 整 数 ( 如 4 和 5) 后 回 车, 将 直 接 显 示 求 和 的 结 果, 如 图 13-8 所 示 图 实 训 要 求 (1) 复 习 教 材 中 和 实 训 相 关 的 内 容, 掌 握 C++ 程 序 的 上 机 步 骤 (2) 整 理 上 机 结 果, 总 结 C++ 程 序 的 上 机 过 程 (3) 完 成 实 训 报 告 13.2 实 训 2 简 单 C++ 程 序 设 计 1. 实 训 目 的 (1) 熟 悉 C++ 语 言 中 基 本 数 据 类 型 变 量 和 常 量 的 应 用, 能 够 灵 活 运 用 各 种 运 算 符 构 造 出
237 228 C++ 程 序 设 计 不 同 的 表 达 式 (2) 练 习 使 用 简 单 的 输 入 输 出 (3) 学 习 使 用 VC 集 成 环 境 中 的 debug 调 试 功 能 : 单 步 执 行 设 置 断 点 和 观 察 变 量 值 (4) 能 够 编 写 简 单 的 C++ 程 序, 进 一 步 熟 悉 C++ 程 序 的 创 建 编 辑 编 译 和 运 行 过 程 2. 实 训 内 容 (1) 从 键 盘 输 入 一 个 小 写 字 母, 按 顺 序 输 出 该 字 母 及 其 前 后 两 个 字 母, 同 时 输 出 其 对 应 的 ASCII 码 值 例 如, 输 入 b 后, 应 输 出 a,b,c 及 其 ASCII 码 值 97,98,99 如 果 输 入 不 符 合 要 求, 能 够 给 出 相 应 的 提 示 信 息 要 求 程 序 调 试 正 确 无 误, 正 确 显 示 运 行 结 果 (2) 编 程 计 算 圆 矩 形 和 三 角 形 的 面 积 运 行 程 序 时 先 提 示 用 户 选 择 图 形 类 型, 如 果 用 户 选 择 圆 形, 则 提 示 用 户 输 入 半 径 值 ; 如 果 用 户 选 择 矩 形, 则 提 示 用 户 输 入 长 和 宽 的 值 最 后, 计 算 出 图 形 的 面 积 并 显 示 3. 实 训 操 作 步 骤 (1) 创 建 一 个 C++ 源 程 序 shixun2_1.cpp, 满 足 实 训 要 求 shixun2_1.cpp 参 考 程 序 如 下 : #include"iostream.h" void main() char x; cin>>x; if(x<'a' x>'z') cout<<" 错 误, 请 重 新 输 入 字 母!"<<endl; else cout<<char(x 1)<<","<<x<<","<<char(x+1)<<endl; cout<<int(x 1)<<","<<int(x)<<","<<int(x+1)<<endl; 程 序 运 行 后, 显 示 结 果 如 图 13-9 和 图 所 示 图 13-9 图 (2) 新 建 一 个 C++ 源 程 序 shixun2_2.cpp, 计 算 图 形 的 面 积 圆 的 面 积 公 式 为 S = PI * r * r,
238 第 13 章 实 训 229 矩 形 的 面 积 公 式 为 S = a * b 程 序 中 定 义 一 个 整 型 变 量 itype 表 示 图 形 类 型 程 序 运 行 时, 首 先 利 用 cout 语 句 提 示 用 户 选 择 图 形 类 型, 用 cin 语 句 接 受 用 户 选 择 的 图 形 类 型, 然 后 用 switch 语 句 判 断 用 户 选 择 的 图 形 类 型, 并 分 别 提 示 用 户 输 入 计 算 面 积 所 需 的 参 数, 最 后 计 算 图 形 的 面 积 并 显 示 程 序 的 运 行 结 果 如 图 和 图 所 示 图 图 shixun2_2.cpp 参 考 程 序 如 下 : #include"iostream.h" const float PI=3.1416; void main() int itype; float r,a,b,area; cout<<" 图 形 类 型 为?(1 圆 形,2 矩 形 ):"; cin>>itype; switch(itype) case 1: cout<<" 圆 的 半 径 为 :"; cin>>r; area=pi*r*r; cout<<" 圆 的 面 积 为 :"<<area<<endl; break; case 2: cout<<" 矩 形 的 长 为 :"; cin>>a; cout<<" 矩 形 的 宽 为 :"; cin>>b; area=a*b; cout<<" 矩 形 的 面 积 为 :"<<area<<endl; break; default:
239 230 C++ 程 序 设 计 cout<<" 不 是 合 法 的 输 入 值!"<<endl; (3) 利 用 debug 调 试 功 能 调 试 程 序 Visual C 集 成 开 发 环 境 提 供 了 辅 助 调 试 工 具, 可 以 实 现 单 步 运 行 设 置 断 点 观 察 变 量 和 表 达 式 的 值 等 功 能, 使 用 户 可 以 跟 踪 程 序 的 执 行 过 程, 观 察 不 同 时 刻 变 量 值 的 变 化 情 况 断 点 就 是 程 序 运 行 时 的 暂 停 点, 程 序 运 行 到 断 点 处 便 暂 停, 这 样 就 可 以 通 过 观 察 断 点 处 变 量 的 值 来 了 解 程 序 的 执 行 过 程 1 首 先 在 第 7 行 处 设 置 断 点, 用 鼠 标 右 键 单 击 第 7 行 的 空 白 处, 将 弹 出 一 个 快 捷 菜 单 在 该 菜 单 中, 选 择 Insert/Remove Breakpoint 选 项, 可 看 到 第 7 行 左 边 的 边 框 上 出 现 了 一 个 褐 色 的 圆 点, 表 示 已 经 在 这 里 设 置 了 一 个 断 点, 如 图 所 示 图 然 后 选 择 编 译 / 开 始 调 试 / 去 菜 单 命 令, 或 按 快 捷 键 F5, 使 系 统 进 入 Debug 调 试 状 态, 程 序 开 始 运 行, 一 个 DOS 窗 口 出 现, 程 序 暂 停 在 断 点 处 此 时 的 Visual C 界 面 如 图 所 示 用 户 会 发 现 多 出 两 个 窗 口, 分 别 是 变 量 窗 口 (Variables Window) 和 观 察 窗 口 (Watch Window) 如 果 没 有 出 现 这 两 个 窗 口, 可 通 过 单 击 查 看 / 调 试 窗 口 中 相 应 的 菜 单 命 令 来 打 开 3 单 步 执 行 在 Debug 菜 单 中 单 击 Step Over 命 令 两 次, 然 后 在 程 序 运 行 后 出 现 的 DOS 窗 口 中 输 入 选 择 的 图 形 类 型 ( 例 如 输 入 2, 选 择 矩 形 ), 这 时 回 到 Visual C 集 成 环 境 中, 在 变 量 窗 口 中 会 发 现 变 量 itype 右 边 出 现 了 变 量 值 2, 如 图 所 示
240 第 13 章 实 训 231 图 图 在 观 察 窗 口 中 的 Name 栏 中 输 入 itype, 回 车, 可 看 到 Value 栏 中 出 现 itype 的 变 量 值 2, 如 图 所 示
241 232 C++ 程 序 设 计 图 继 续 执 行 程 序, 参 照 上 述 方 法, 试 试 其 他 变 量, 进 一 步 熟 悉 Debug 调 试 功 能 4. 实 训 要 求 (1) 整 理 上 机 结 果, 掌 握 VC 集 成 环 境 中 的 debug 调 试 功 能 (2) 完 成 实 训 报 告 13.3 实 训 3 控 制 语 句 1. 实 训 目 的 (1) 掌 握 表 达 式 语 句 复 合 语 句 选 择 语 句 循 环 语 句 和 转 移 语 句 的 使 用 (2) 熟 练 使 用 if 和 switch 语 句 实 现 选 择 结 构 (3) 熟 练 使 用 while,do while 和 for 语 句 实 现 循 环 结 构 2. 实 训 内 容 (1) 分 别 用 if 和 switch 语 句 计 算 并 输 出 下 面 的 分 段 函 数 1 y = 0 1 x>0 x 0 x = 0 <x 0 (2) 输 入 某 员 工 的 基 本 工 资, 由 基 本 工 资 计 算 增 加 后 的 工 资 增 加 的 条 件 为 : 如 果 原 工 资 大 于 等 于 600 元, 则 增 加 原 工 资 的 0.2 倍 ; 如 果 原 工 资 大 于 等 于 400 元 而 且 小 于 600 元, 则 增 加 原 工 资 的 0.15 倍 ; 其 余 则 增 加 原 工 资 的 0.1 倍
242 第 13 章 实 训 233 (3) 编 程 计 算 1~100 的 累 加 和, 并 输 出 显 示 结 果 (4) 编 程 输 出 下 列 图 案 * *** ***** *** * (5) 输 入 3 个 不 同 的 数, 将 它 们 从 大 到 小 排 序 3. 实 训 操 作 步 骤 ( 略 ) 4. 实 训 要 求 (1) 整 理 上 机 结 果, 完 成 实 训 报 告 (2) 注 意 总 结 上 机 体 会 13.4 实 训 4 函 数 的 应 用 1. 实 训 目 的 (1) 掌 握 函 数 定 义 函 数 调 用 和 函 数 原 型 说 明 的 方 法 (2) 掌 握 函 数 嵌 套 调 用 和 递 归 调 用 的 方 法 (3) 掌 握 全 局 变 量 局 部 变 量 的 概 念 和 使 用 方 法 (4) 掌 握 内 联 函 数 重 载 函 数 的 使 用 方 法 (5) 熟 练 C++ 的 系 统 函 数 2. 实 训 内 容 (1) 运 行 下 面 的 程 序 并 分 析 结 果 #include"iostream.h" int n; int fun(int x); void main() int a=5,b; b=fun(a); cout<<" 主 函 数 的 a="<<a<<endl; cout<<" 主 函 数 的 b="<<a<<endl; cout<<" 全 局 变 量 n="<<n<<endl; a++; b=fun(a); cout<<" 主 函 数 的 a="<<a<<endl; cout<<" 主 函 数 的 b="<<a<<endl; cout<<" 全 局 变 量 n="<<n<<endl;
243 234 C++ 程 序 设 计 int fun(int x) int a=1; static int b=10; a++; b++; x++; n++; cout<<"fun 函 数 的 a="<<a<<endl; cout<<"fun 函 数 的 b="<<a<<endl; cout<<" 全 局 变 量 n="<<n<<endl; return(a+b+x); (2) 编 写 温 度 转 换 函 数, 实 现 将 华 氏 温 度 F 转 换 为 摄 氏 温 度 C 转 换 公 式 为 C= (F 32) *5/9 在 main 函 数 中 实 现 输 入 和 输 出 (3) 编 写 重 载 函 数 Max1, 分 别 求 取 两 个 整 数 3 个 整 数 两 个 双 精 度 数 和 3 个 双 精 度 数 的 最 大 值 (4) 上 机 运 行 第 3 章 中 例 3.7 的 Hanoi( 汉 诺 ) 塔 游 戏 3. 实 训 操 作 步 骤 参 照 实 训 1, 编 辑 调 试 并 运 行 程 序, 输 出 正 确 结 果 4. 实 训 要 求 (1) 复 习 教 材 中 和 实 训 相 关 的 内 容, 提 前 编 好 程 序 (2) 整 理 上 机 结 果, 完 成 实 训 报 告 (3) 注 意 总 结 上 机 体 会 13.5 实 训 5 数 组 的 使 用 1. 实 训 目 的 (1) 掌 握 数 组 定 义 的 规 则 (2) 掌 握 数 组 的 初 始 化 方 法 和 数 组 元 素 的 引 用 (3) 熟 悉 字 符 串 处 理 函 数 的 使 用 2. 实 训 内 容 (1) 调 用 随 机 函 数 rand(), 产 生 10 个 100~500 之 间 的 随 机 数 存 入 数 组 a 中, 显 示 所 有 数 组 元 素 然 后, 用 选 择 排 序 法 对 这 10 个 元 素 按 递 增 顺 序 进 行 排 序, 输 出 排 序 后 的 结 果 1 选 择 排 序 法 : 在 n 个 元 素 中 选 择 最 小 的 一 个 元 素, 把 它 和 位 于 第 1 个 位 置 的 元 素 互 换 位 置, 然 后 在 剩 余 的 n 1 个 元 素 中 选 择 最 小 的 一 个 元 素, 把 它 和 位 于 第 2 个 位 置 的 元 素 互 换 位 置 不 断 重 复 上 述 步 骤, 直 到 最 后 两 个 元 素 2 rand() 函 数 : 该 函 数 能 产 生 一 个 值 在 0~RAND_MAX 之 间 的 伪 随 机 数,RAND_MAX 在 stdlib.h 中 定 义, 其 值 为 , 可 用 表 达 式 rand()% 来 产 生 100~500 之 间 的 随 机 数
244 第 13 章 实 训 思 考 : 如 果 要 实 现 递 减 排 序, 应 如 何 修 改 程 序? (2) 定 义 一 个 二 维 数 组, 存 入 5 个 学 生 的 数 学 语 文 英 语 物 理 和 化 学 5 门 课 程 的 成 绩, 计 算 并 输 出 每 一 门 课 程 的 平 均 成 绩 和 每 一 位 学 生 的 平 均 成 绩 (3) 编 程 实 现 顺 序 读 入 一 串 数 据, 不 限 定 数 据 个 数, 以 相 反 的 次 序 输 出 所 有 的 数 据 例 如, 输 入 1234, 输 出 4321 思 考 : 对 不 同 的 数 据 类 型 ( 如 int,double 及 long 等 ), 应 如 何 修 改 程 序? 当 输 入 的 是 字 符 串 时, 若 以 空 格 作 为 结 束 符, 应 如 何 修 改 程 序? (4) 输 入 两 个 字 符 串, 比 较 这 两 个 字 符 串 是 否 相 同, 并 输 出 不 同 的 比 较 结 果 3. 实 训 操 作 步 骤 ( 略 ) 4. 实 训 要 求 (1) 复 习 教 材 中 和 实 训 相 关 的 内 容, 提 前 编 好 程 序 (2) 整 理 上 机 结 果, 完 成 实 训 报 告, 给 出 思 考 题 的 解 决 方 案 (3) 注 意 总 结 上 机 体 会 13.6 实 训 6 结 构 体 和 共 用 体 1. 实 训 目 的 (1) 掌 握 结 构 体 变 量 定 义 和 使 用 的 方 法 (2) 掌 握 结 构 体 数 组 定 义 和 使 用 的 方 法 2. 实 训 内 容 (1) 定 义 一 个 结 构 体, 包 含 year,month 和 day 三 个 成 员 运 行 程 序 时, 用 户 按 照 提 示 信 息 输 入 年 月 日 等 信 息, 然 后 在 屏 幕 上 格 式 输 出 当 前 的 日 期 (2) 定 义 一 个 含 有 20 个 元 素 的 结 构 体 数 组, 用 来 存 储 20 个 学 生 的 个 人 资 料, 其 中 包 括 学 生 的 学 号 姓 名 性 别 年 龄 班 级 和 联 系 电 话 等 信 息 当 输 入 要 查 询 学 生 的 学 号 时, 能 够 显 示 该 学 生 的 个 人 资 料 3. 实 训 操 作 步 骤 ( 略 ) 4. 实 训 要 求 (1) 复 习 教 材 中 和 实 训 相 关 的 内 容, 提 前 编 好 程 序 (2) 整 理 上 机 结 果, 完 成 实 训 报 告 (3) 注 意 总 结 上 机 体 会 13.7 实 训 7 指 针 的 使 用 1. 实 训 目 的 (1) 掌 握 指 针 的 概 念, 掌 握 指 针 定 义 和 使 用 的 方 法 (2) 掌 握 数 组 指 针 和 指 向 数 组 的 指 针 变 量 (3) 掌 握 指 针 作 为 函 数 参 数 的 使 用 方 法 2. 实 训 内 容 (1) 使 用 指 针 变 量 实 现 数 组 元 素 按 逆 序 重 新 排 列 要 求 在 main() 函 数 中 实 现 对 数 组 赋 值 和
245 236 C++ 程 序 设 计 输 出 排 序 结 果 (2) 使 用 指 针 变 量 实 现 自 定 义 的 可 求 取 字 符 串 长 度 的 函 数 要 求 在 main() 函 数 中 输 入 字 符 串 并 输 出 长 度 值 (3) 随 意 输 入 6 个 数 值, 将 这 6 个 数 存 入 数 组 m 中, 编 程 计 算 其 中 偶 数 的 和 及 奇 数 的 和 (4) 编 程 实 现 从 键 盘 输 入 10 个 数, 找 出 其 中 的 最 大 数 及 其 位 置 3. 实 训 操 作 步 骤 ( 略 ) 4. 实 训 要 求 (1) 复 习 教 材 中 和 实 训 相 关 的 内 容, 提 前 编 好 程 序 (2) 整 理 上 机 结 果, 完 成 实 训 报 告 (3) 注 意 总 结 上 机 体 会 13.8 实 训 8 类 与 数 据 抽 象 1. 实 训 目 的 (1) 掌 握 类 和 对 象 的 定 义 和 使 用 (2) 掌 握 构 造 函 数 和 析 构 函 数 的 定 义 和 执 行 过 程 (3) 掌 握 成 员 函 数 的 重 载 2. 实 训 内 容 (1) 设 计 一 个 点 类 Point, 要 求 给 出 一 个 点 的 坐 标, 可 以 写 出 三 维 坐 标 形 式 (x, y, z) 实 例 化 两 个 点 对 象, 计 算 两 点 之 间 的 距 离, 并 输 出 显 示 结 果 (2) 声 明 一 个 时 钟 类, 包 含 小 时 Hour 分 钟 Minutes 和 秒 Second 3 个 数 据 成 员, 有 两 个 公 有 成 员 函 数, 分 别 是 时 间 设 置 函 数 SetTime(int NewH=0,int NewM=0,int NewS=0) 和 时 间 显 示 函 数 ShowTime() 在 主 函 数 main() 中, 利 用 时 间 设 置 函 数 SetTime 设 置 时 间, 当 调 用 时 间 显 示 函 数 ShowTime() 时 就 显 示 设 置 的 时 间 (3) 设 计 一 个 类, 要 求 声 明 一 个 构 造 函 数 和 一 个 析 构 函 数, 定 义 一 个 私 有 的 数 据 成 员, 用 构 造 函 数 进 行 初 始 化, 验 证 构 造 函 数 和 析 构 函 数 的 生 成 顺 序 及 作 用 (4) 编 写 3 个 名 为 add 的 重 载 函 数, 分 别 实 现 两 个 整 数 相 加 两 个 单 精 度 数 相 加 以 及 两 个 双 精 度 数 相 加 3. 实 训 操 作 步 骤 ( 略 ) 4. 实 训 要 求 (1) 复 习 教 材 中 和 实 训 相 关 的 内 容, 提 前 编 好 程 序 (2) 整 理 上 机 结 果, 完 成 实 训 报 告 (3) 注 意 总 结 上 机 体 会 1. 实 训 目 的 (1) 理 解 运 算 符 重 载 的 意 义 (2) 掌 握 运 算 符 重 载 的 实 现 方 法 13.9 实 训 9 运 算 符 重 载
246 第 13 章 实 训 实 训 内 容 (1) 利 用 运 算 符 重 载 的 方 法 重 载 运 算 符 +, 实 现 两 个 复 数 的 相 加 (2) 编 写 程 序, 利 用 成 员 函 数 重 载 运 算 符 + 和, 实 现 将 两 个 二 维 数 组 相 加 或 相 减 要 求 第 一 个 二 维 数 组 的 值 由 构 造 函 数 设 置, 第 二 个 二 维 数 组 的 值 由 键 盘 输 入 3. 实 训 操 作 步 骤 ( 略 ) 4. 实 训 要 求 (1) 复 习 教 材 中 和 实 训 相 关 的 内 容, 提 前 编 好 程 序 (2) 整 理 上 机 结 果, 完 成 实 训 报 告 (3) 注 意 总 结 上 机 体 会 实 训 10 继 承 性 和 派 生 1. 实 训 目 的 (1) 学 习 类 的 继 承, 能 够 定 义 和 使 用 类 的 继 承 关 系 (2) 掌 握 派 生 类 的 声 明 和 定 义 方 法 (3) 熟 悉 公 有 派 生 类 和 私 有 派 生 类 的 访 问 特 性 (4) 学 习 利 用 虚 基 类 在 解 决 二 义 性 问 题 中 的 作 用 2. 实 训 内 容 (1) 定 义 一 个 基 类 Animal, 有 私 有 整 型 成 员 变 量 Age, 构 造 其 派 生 类 Dog, 在 其 成 员 函 数 Setage(int n) 中 直 接 给 age 赋 初 值, 看 看 会 有 什 么 问 题 把 Age 改 为 公 有 整 型 成 员 变 量, 还 会 出 问 题 吗? 观 察 程 序 运 行 结 果 (2) 定 义 一 个 车 类 Vehicle, 具 有 最 大 速 度 Maxspeed 重 量 Weight 等 成 员 变 量, 行 驶 Run 停 车 Stop 等 成 员 函 数, 由 此 派 生 出 自 行 车 类 Bicycle 汽 车 类 Car 自 行 车 类 有 颜 色 Color 等 属 性, 汽 车 类 有 车 型 Type 等 属 性, 从 自 行 车 类 和 汽 车 类 派 生 出 摩 托 车 类 Motor 在 继 承 过 程 中, 注 意 把 车 类 Vehicle 设 置 为 虚 基 类 如 果 不 把 Vehicle 设 置 为 虚 基 类, 会 有 什 么 问 题? 观 察 程 序 运 行 结 果 3. 实 训 操 作 步 骤 ( 略 ) 4. 实 训 要 求 (1) 复 习 教 材 中 和 实 训 相 关 的 内 容, 提 前 编 好 程 序 (2) 整 理 上 机 结 果, 完 成 实 训 报 告 (3) 注 意 总 结 上 机 体 会 实 训 11 虚 函 数 和 多 态 性 1. 实 训 目 的 (1) 掌 握 虚 函 数 的 定 义 和 使 用 方 法 (2) 理 解 多 态 性 (3) 学 习 使 用 虚 函 数 实 现 多 态 性 的 方 法 2. 实 训 内 容 (1) 定 义 一 个 类 Basefly, 该 类 中 有 一 个 Fly() 函 数 定 义 3 个 类 Birdfly,Dragonfly 和 Planefly,
247 238 C++ 程 序 设 计 都 继 承 自 Basefly 类, 并 重 载 Fly() 函 数 用 各 类 的 指 针 调 用 各 个 类 的 对 象 的 Fly() 函 数, 体 会 继 承 中 的 多 态 性 将 Basefly::Fly() 函 数 声 明 为 虚 函 数, 体 会 虚 函 数 在 多 态 性 中 的 应 用 (2) 定 义 一 个 表 示 学 生 的 类 XS, 包 括 成 员 函 数 XM(),XB() 和 NL(), 分 别 用 来 显 示 学 生 的 姓 名 性 别 和 年 龄, 并 将 它 们 全 部 定 义 为 虚 函 数 定 义 一 个 类 CZS 表 示 初 中 生, 包 含 数 据 成 员 xm,xb 和 nl, 分 别 表 示 初 中 生 的 姓 名 性 别 和 年 龄 ; 包 括 成 员 函 数 XM(),XB() 和 NL(), 分 别 用 来 显 示 初 中 生 的 姓 名 性 别 和 年 龄 再 定 义 一 个 类 GZS 表 示 高 中 生 和 一 个 类 DXS 表 示 大 学 生, 同 样 包 含 数 据 成 员 xm,xb 和 nl, 也 包 括 成 员 函 数 XM(),XB() 和 NL() 1 设 计 基 类 XS 及 其 派 生 类 CZS,GZS 和 DXS 2 分 别 生 成 CZS,GZS 和 DXS 类 的 对 象 3 将 CZS,GZS 和 DXS 类 对 象 的 指 针 赋 给 XS 类 的 指 针 变 量 4 分 别 用 XS 类 的 指 针 和 引 用 访 问 成 员 函 数 XM(),XB() 和 NL() 5 观 察 程 序 结 果 3. 实 训 操 作 步 骤 ( 略 ) 4. 实 训 要 求 (1) 复 习 教 材 中 和 实 训 相 关 的 内 容, 提 前 编 好 程 序 (2) 整 理 上 机 结 果, 完 成 实 训 报 告 (3) 注 意 总 结 上 机 体 会 1. 实 训 目 的 实 训 12 输 入 / 输 出 流 (1) 掌 握 流 类 中 的 常 用 类 及 其 成 员 函 数 的 用 法 (2) 学 习 标 准 输 入 / 输 出 及 格 式 控 制 2. 实 训 内 容 (1) 按 照 下 面 的 格 式 要 求 输 出 数 据 1 以 8 个 字 符 的 宽 度 输 出 数 字 2003, 采 用 右 对 齐 方 式, 多 余 部 分 用 * 填 充 2 以 5 位 数 的 精 度 输 出 显 示 数 字 以 10 个 字 符 的 宽 度 输 出 字 符 Welcome, 采 用 左 对 齐 方 式, 多 余 部 分 用 * 填 充 4 以 十 六 进 制 形 式 输 出 数 字 13 (2) 设 计 一 个 程 序, 接 受 用 户 的 多 行 输 入, 用 户 输 入 Ctrl+Z 表 示 输 入 结 束 程 序 接 收 完 所 有 输 入 后, 再 将 输 入 内 容 全 部 显 示 出 来 1 分 析 控 制 台 输 入 / 输 出 的 要 求 2 掌 握 键 盘 输 入 和 屏 幕 显 示 的 编 程 方 法 3. 实 训 操 作 步 骤 ( 略 ) 4. 实 训 要 求 (1) 复 习 教 材 中 和 实 训 相 关 的 内 容, 提 前 编 好 程 序 (2) 整 理 上 机 结 果, 完 成 实 训 报 告 (3) 注 意 总 结 上 机 体 会
248 第 13 章 实 训 实 训 13 文 件 处 理 1. 实 训 目 的 (1) 掌 握 文 件 常 用 的 处 理 方 法 (2) 掌 握 顺 序 文 件 和 随 机 文 件 的 读 写 方 法 2. 实 训 内 容 (1) 设 计 一 个 留 言 类, 实 现 以 下 功 能 1 新 建 一 个 名 为 c:\out.txt 的 空 文 本 文 件, 将 用 户 输 入 的 信 息 写 入 该 文 件 2 以 后 每 次 运 行 时, 都 先 读 取 该 文 件 的 内 容 并 显 示 给 用 户, 然 后 由 用 户 输 入 新 的 信 息, 退 出 时 将 新 的 信 息 存 入 这 个 文 档 (2) 编 程 实 现 将 文 本 文 件 abcin.txt 中 的 小 写 字 母 都 转 换 成 大 写 字 母, 并 输 出 到 abcout.txt 文 件 中, 然 后 显 示 abcout.txt 文 件 中 的 内 容 并 统 计 字 符 个 数 3. 实 训 操 作 步 骤 ( 略 ) 4. 实 训 要 求 (1) 复 习 教 材 中 和 实 训 相 关 的 内 容, 提 前 编 好 程 序 (2) 整 理 上 机 结 果, 完 成 实 训 报 告 (3) 注 意 总 结 上 机 体 会
249 参 考 文 献 [1] 吕 凤 翥.C++ 语 言 基 础 教 程. 清 华 大 学 出 版 社,2002 [2] 余 苏 宁.C++ 程 序 设 计. 高 等 教 育 出 版 社,2004 [3] 艾 德 才.C++ 程 序 设 计 简 明 教 程 ( 修 订 版 ). 中 国 水 利 水 电 出 版 社,2003 [4] 郑 莉, 刘 慧 宁, 孟 威.C++ 程 序 设 计 教 程. 机 械 工 业 出 版 社,2001 [5] 周 蔼 如, 林 伟 健.C++ 程 序 设 计 基 础. 电 子 工 业 出 版 社,2003 [6] 李 龙 澍.C++ 程 序 设 计. 清 华 大 学 出 版 社,2003 [7] 马 建 红, 沈 西 挺.Visual C++ 程 序 设 计 与 软 件 技 术 基 础. 中 国 水 利 水 电 出 版 社.2002 [8] 谭 浩 强. 面 向 对 象 的 C++ 程 序 设 计. 电 子 工 业 出 版 社,2002 [9] 徐 孝 凯.C++ 语 言 程 序 设 计. 清 华 大 学 出 版 社,2003 [10] 陈 维 兴, 林 小 茶.C++ 面 向 对 象 程 序 设 计. 中 国 铁 道 出 版 社,2004 [11] 蔡 立 军 杜 四 春 银 红 霞.C++ 程 序 设 计 实 验 指 导 与 实 训. 中 国 水 利 水 电 出 版 社,2004 [12] 郑 莉 傅 仕 星.C++ 语 言 程 序 设 计 习 题 与 实 验 指 导. 清 华 大 学 出 版 社,2000 [13] 吴 访 升.C++ 程 序 设 计 学 习 指 导 与 上 机 实 践. 机 械 工 业 出 版 社,2002 [14] 张 玲 席 德 春 刘 晓 杰.C++ 上 机 实 践 指 导 教 程. 机 械 工 业 出 版 社,2004
新版 明解C++入門編
511!... 43, 85!=... 42 "... 118 " "... 337 " "... 8, 290 #... 71 #... 413 #define... 128, 236, 413 #endif... 412 #ifndef... 412 #if... 412 #include... 6, 337 #undef... 413 %... 23, 27 %=... 97 &... 243,
新版 明解C言語入門編
328, 4, 110, 189, 103, 11... 318. 274 6 ; 10 ; 5? 48 & & 228! 61!= 42 ^= 66 _ 82 /= 66 /* 3 / 19 ~ 164 OR 53 OR 164 = 66 ( ) 115 ( ) 31 ^ OR 164 [] 89, 241 [] 324 + + 4, 19, 241 + + 22 ++ 67 ++ 73 += 66
CC213
: (Ken-Yi Lee), E-mail: [email protected] 49 [P.51] C/C++ [P.52] [P.53] [P.55] (int) [P.57] (float/double) [P.58] printf scanf [P.59] [P.61] ( / ) [P.62] (char) [P.65] : +-*/% [P.67] : = [P.68] : ,
untitled
1 Outline 數 料 數 數 列 亂數 練 數 數 數 來 數 數 來 數 料 利 料 來 數 A-Z a-z _ () 不 數 0-9 數 不 數 SCHOOL School school 數 讀 school_name schoolname 易 不 C# my name 7_eleven B&Q new C# (1) public protected private params override
新・解きながら学ぶJava
481! 41, 74!= 40, 270 " 4 % 23, 25 %% 121 %c 425 %d 121 %o 121 %x 121 & 199 && 48 ' 81, 425 ( ) 14, 17 ( ) 128 ( ) 183 * 23 */ 3, 390 ++ 79 ++ 80 += 93 + 22 + 23 + 279 + 14 + 124 + 7, 148, 16 -- 79 --
nooog
C : : : , C C,,, C, C,, C ( ), ( ) C,,, ;,, ; C,,, ;, ;, ;, ;,,,, ;,,, ; : 1 9, 2 3, 4, 5, 6 10 11, 7 8, 12 13,,,,, 2008 1 1 (1 ) 1.1 (1 ) 1.1.1 ( ) 1.1.2 ( ) 1.1.3 ( ) 1.1.4 ( ) 1.1.5 ( ) 1.2 ( ) 1.2.1
新・解きながら学ぶC言語
330!... 67!=... 42 "... 215 " "... 6, 77, 222 #define... 114, 194 #include... 145 %... 21 %... 21 %%... 21 %f... 26 %ld... 162 %lf... 26 %lu... 162 %o... 180 %p... 248 %s... 223, 224 %u... 162 %x... 180
( CIP) /. :, ( ) ISBN TP CIP ( 2005) : : : : * : : 174 ( A ) : : ( 023) : ( 023)
( CIP) /. :, 2005. 2 ( ) ISBN 7-5624-3339-9.......... TP311. 1 CIP ( 2005) 011794 : : : : * : : 174 ( A ) :400030 : ( 023) 65102378 65105781 : ( 023) 65103686 65105565 : http: / /www. cqup. com. cn : fxk@cqup.
新・明解C言語入門編『索引』
!... 75!=... 48 "... 234 " "... 9, 84, 240 #define... 118, 213 #include... 148 %... 23 %... 23, 24 %%... 23 %d... 4 %f... 29 %ld... 177 %lf... 31 %lu... 177 %o... 196 %p... 262 %s... 242, 244 %u... 177
Microsoft Word - 01.DOC
第 1 章 JavaScript 简 介 JavaScript 是 NetScape 公 司 为 Navigator 浏 览 器 开 发 的, 是 写 在 HTML 文 件 中 的 一 种 脚 本 语 言, 能 实 现 网 页 内 容 的 交 互 显 示 当 用 户 在 客 户 端 显 示 该 网 页 时, 浏 览 器 就 会 执 行 JavaScript 程 序, 用 户 通 过 交 互 式 的
提问袁小兵:
C++ 面 试 试 题 汇 总 柯 贤 富 管 理 软 件 需 求 分 析 篇 1. STL 类 模 板 标 准 库 中 容 器 和 算 法 这 部 分 一 般 称 为 标 准 模 板 库 2. 为 什 么 定 义 虚 的 析 构 函 数? 避 免 内 存 问 题, 当 你 可 能 通 过 基 类 指 针 删 除 派 生 类 对 象 时 必 须 保 证 基 类 析 构 函 数 为 虚 函 数 3.
_汪_文前新ok[3.1].doc
普 通 高 校 本 科 计 算 机 专 业 特 色 教 材 精 选 四 川 大 学 计 算 机 学 院 国 家 示 范 性 软 件 学 院 精 品 课 程 基 金 青 年 基 金 资 助 项 目 C 语 言 程 序 设 计 (C99 版 ) 陈 良 银 游 洪 跃 李 旭 伟 主 编 李 志 蜀 唐 宁 九 李 涛 主 审 清 华 大 学 出 版 社 北 京 i 内 容 简 介 本 教 材 面 向
untitled
A, 3+A printf( ABCDEF ) 3+ printf( ABCDEF ) 2.1 C++ main main main) * ( ) ( ) [ ].* ->* ()[] [][] ** *& char (f)(int); ( ) (f) (f) f (int) f int char f char f(int) (f) char (*f)(int); (*f) (int) (
C 1
C homepage: xpzhangme 2018 5 30 C 1 C min(x, y) double C // min c # include # include double min ( double x, double y); int main ( int argc, char * argv []) { double x, y; if( argc!=
得 到 了 補 償. 對 於 武 姜 而 言, 莊 公 與 自 己 的 關 係 並 不 親 密, 而 共 叔 段 又 是 自 己 向 來 疼 愛 有 加 的 兒 子, 所 以, 對 莊 公 提 出 再 怎 麼 無 理 的 要 求, 武 姜 也 不 會 覺 得 有 什 麼 不 妥 之 處, 而 對 共
左 傳 - 鄭 伯 克 段 於 鄢 人 物 心 理 1021141 林 詩 倩 一. 緒 論 鄭 伯 克 段 於 鄢, 及 共 叔 段 之 亂, 是 魯 隱 公 元 年, 即 公 元 前 722 年, 春 秋 初 年 在 鄭 國 國 內 發 生 的 一 場 內 亂. 武 姜 成 為 武 公 夫 人 並 先 後 為 武 公 生 下 了 兩 個 兒 子, 長 子 莊 公 由 於 腳 先 出 來 造 成
一 耀 州 青 瓷 的 裝 飾 手 法 與 紋 飾 種 類 耀 州 窯 的 裝 飾 紋 樣, 豐 富 多 變, 而 且 題 材 內 容 廣 泛, 組 合 形 式 多 樣, 圖 案 形 象 優 美, 令 人 賞 心 悅 目, 並 且 反 映 了 當 時 社 會 的 審 美 趣 味 和 理 想 裝 飾
宋 代 耀 州 青 瓷 的 紋 飾 風 格 與 意 義 曾 肅 良 英 國 萊 斯 特 大 學 博 物 館 學 博 士 國 立 台 灣 師 範 大 學 美 術 研 究 所 助 理 教 授 摘 要 中 國 的 飲 茶 之 風, 興 於 唐 而 盛 於 宋, 特 別 是 宋 代 宮 廷 禁 苑 和 地 方 官 吏 文 人 學 士 的 尚 茶 崇 茶, 以 品 茶 為 雅 尚 的 觀 念 與 作 法, 使
int *p int a 0x00C7 0x00C7 0x00C int I[2], *pi = &I[0]; pi++; char C[2], *pc = &C[0]; pc++; float F[2], *pf = &F[0]; pf++;
Memory & Pointer [email protected] 2.1 2.1.1 1 int *p int a 0x00C7 0x00C7 0x00C7 2.1.2 2 int I[2], *pi = &I[0]; pi++; char C[2], *pc = &C[0]; pc++; float F[2], *pf = &F[0]; pf++; 2.1.3 1. 2. 3. 3 int A,
Ps22Pdf
C ( CIP) C /. :, 2001. 7 21 ISBN 7-5624 -2355-5. C........ C. TP312 CIP ( 2001 ) 034496 C * * : 7871092 1 /16 : 14. 25 : 356 20017 1 20017 1 : 1 6 000 ISBN 7-5624-2355-5 / TP311 : 21. 00 C, C,,,, C,, (
(procedure-oriented)?? 2
1 (procedure-oriented)?? 2 (Objected-Oriented) (class)? (method)? 3 : ( 4 ???? 5 OO 1966 Kisten Nygaard Ole-Johan Dahl Simula Simula 爲 6 Smalltalk Alan Kay 1972 PARC Smalltalk Smalltalk 爲 Smalltalk 爲 Smalltalk
C/C++语言 - C/C++数据
C/C++ C/C++ Table of contents 1. 2. 3. 4. char 5. 1 C = 5 (F 32). 9 F C 2 1 // fal2cel. c: Convert Fah temperature to Cel temperature 2 # include < stdio.h> 3 int main ( void ) 4 { 5 float fah, cel ;
## $%& %& ## () #) (( * (+++ () #) #) (+ (+ #) #) ( #, - #)). #))- # ( / / / 0 1 2 0 / $ # ( *. 3. 3 *..# 4 #$ 3 ( 5 ) ### 4 $ # 5, $ ## # 4 $# 5 ( %
# # $ %& $ %# ( $ # ( # $ ( $ $ ( ( % ( $ ( $ ( ( % ( % $ ( $ ( ( $ ( ( ( & ( ( ( $ ( ( % %# ( ( $ ( %# % ## $%& %& ## () #) (( * (+++ () #) #) (+ (+ #) #) ( #, - #)). #))- # ( / / / 0 1 2 0 / $ # ( *.
1 Project New Project 1 2 Windows 1 3 N C test Windows uv2 KEIL uvision2 1 2 New Project Ateml AT89C AT89C51 3 KEIL Demo C C File
51 C 51 51 C C C C C C * 2003-3-30 [email protected] C C C C KEIL uvision2 MCS51 PLM C VC++ 51 KEIL51 KEIL51 KEIL51 KEIL 2K DEMO C KEIL KEIL51 P 1 1 1 1-1 - 1 Project New Project 1 2 Windows 1 3 N C test
51 C 51 isp 10 C PCB C C C C KEIL
http://wwwispdowncom 51 C " + + " 51 AT89S51 In-System-Programming ISP 10 io 244 CPLD ATMEL PIC CPLD/FPGA ARM9 ISP http://wwwispdowncom/showoneproductasp?productid=15 51 C C C C C ispdown http://wwwispdowncom
概述
OPC Version 1.6 build 0910 KOSRDK Knight OPC Server Rapid Development Toolkits Knight Workgroup, eehoo Technology 2002-9 OPC 1...4 2 API...5 2.1...5 2.2...5 2.2.1 KOS_Init...5 2.2.2 KOS_InitB...5 2.2.3
C/C++程序设计 - 字符串与格式化输入/输出
C/C++ / Table of contents 1. 2. 3. 4. 1 i # include # include // density of human body : 1. 04 e3 kg / m ^3 # define DENSITY 1. 04 e3 int main ( void ) { float weight, volume ; int
6 C51 ANSI C Turbo C C51 Turbo C C51 C51 C51 C51 C51 C51 C51 C51 C C C51 C51 ANSI C MCS-51 C51 ANSI C C C51 bit Byte bit sbit
6 C51 ANSI C Turbo C C51 Turbo C C51 C51 C51 C51 C51 C51 C51 C51 C51 6.1 C51 6.1.1 C51 C51 ANSI C MCS-51 C51 ANSI C C51 6.1 6.1 C51 bit Byte bit sbit 1 0 1 unsigned char 8 1 0 255 Signed char 8 11 128
CHAPTER VC#
1. 2. 3. 4. CHAPTER 2-1 2-2 2-3 2-4 VC# 2-5 2-6 2-7 2-8 Visual C# 2008 2-1 Visual C# 0~100 (-32768~+32767) 2 4 VC# (Overflow) 2-1 2-2 2-1 2-1.1 2-1 1 10 10!(1 10) 2-3 Visual C# 2008 10! 32767 short( )
Microsoft PowerPoint - OPVB1基本VB.ppt
大 綱 0.VB 能 做 什 麼? CH1 VB 基 本 認 識 1.VB 歷 史 與 版 本 2.VB 環 境 簡 介 3. 即 時 運 算 視 窗 1 0.VB 能 做 什 麼? Visual Basic =>VB=> 程 式 設 計 語 言 => 設 計 程 式 設 計 你 想 要 的 功 能 的 程 式 自 動 化 資 料 庫 計 算 模 擬 遊 戲 網 路 監 控 實 驗 輔 助 自 動
序
软 件 工 程 思 想 林 锐 序 软 件 工 程 思 想 讲 述 软 件 开 发 和 做 程 序 员 的 道 理, 视 野 独 特, 构 思 新 颖, 内 容 风 趣, 不 落 窠 臼, 令 人 耳 目 一 新 堪 称 难 得, 以 至 回 味 无 穷 作 者 从 事 了 八 年 的 软 件 开 发 工 作, 在 他 的 博 士 学 位 论 文 完 成 之 际 写 下 了 这 本 心 之 所 感
<4D F736F F D20B2C43032B3B920B8EAAEC6ABACBA41BB50AAEDA5DCA6A12E646F63>
C++ î Á 2-1! C Ã Ñ Ó 2-1.1! î ô à i¾ ò{î ~ à } Ñ lf ŠÈx«v ~ C ÃÑ lî nùƒ f d Û Ã ó ÎÛol ƒ à ó dîû Ê óãi Š~ v C v ÃÈxi á «constant Û Ù Ã ˆ ó nù d «12-452 100000 0 d 'A' 'Z' 8.23 0.1232 0.001 ŒÛ~ iñ C++ ó
Microsoft Word - 第3章.doc
Java C++ Pascal C# C# if if if for while do while foreach while do while C# 3.1.1 ; 3-1 ischeck Test() While ischeck while static bool ischeck = true; public static void Test() while (ischeck) ; ischeck
《C语言程序设计》教材习题参考答案
教 材 名 称 : C 语 言 程 序 设 计 ( 第 1 版 ) 黄 保 和 江 弋 编 著 清 华 大 学 出 版 社 ISBN: 978-7-302-13599-9, 红 色 封 面 答 案 制 作 时 间 :2011 年 2 月 -5 月 一 思 考 题 1 常 量 和 变 量 有 什 么 区 别? 它 们 分 别 是 如 何 定 义 的? 常 量 是 指 在 C 程 序 运 行 过 程 中
untitled
1 Outline 料 類 說 Tang, Shih-Hsuan 2006/07/26 ~ 2006/09/02 六 PM 7:00 ~ 9:30 聯 [email protected] www.csie.ntu.edu.tw/~r93057/aspnet134 度 C# 力 度 C# Web SQL 料 DataGrid DataList 參 ASP.NET 1.0 C# 例 ASP.NET 立
全国计算机技术与软件专业技术资格(水平)考试
全 国 计 算 机 技 术 与 软 件 专 业 技 术 资 格 ( 水 平 ) 考 试 2008 年 上 半 年 程 序 员 下 午 试 卷 ( 考 试 时 间 14:00~16:30 共 150 分 钟 ) 试 题 一 ( 共 15 分 ) 阅 读 以 下 说 明 和 流 程 图, 填 补 流 程 图 中 的 空 缺 (1)~(9), 将 解 答 填 入 答 题 纸 的 对 应 栏 内 [ 说 明
(\244j\257d\276\307\274\351_201508021-C.indd_70%.pdf)
1847-1852 1872 20 1 1896 8000 20 1896 1950 1 1896 1896 13 1900 1900 3 20 2 4 1910 1950 3 1911 1 2 3 4 1927 4 20 300 6 1906 1930 7 1911 5 1919 8 1914 9 1920 10 11 1902 200 6 12 1930 7 " # #! $! 14 15! "!
C/C++ - 文件IO
C/C++ IO Table of contents 1. 2. 3. 4. 1 C ASCII ASCII ASCII 2 10000 00100111 00010000 31H, 30H, 30H, 30H, 30H 1, 0, 0, 0, 0 ASCII 3 4 5 UNIX ANSI C 5 FILE FILE 6 stdio.h typedef struct { int level ;
C/C++ - 字符输入输出和字符确认
C/C++ Table of contents 1. 2. getchar() putchar() 3. (Buffer) 4. 5. 6. 7. 8. 1 2 3 1 // pseudo code 2 read a character 3 while there is more input 4 increment character count 5 if a line has been read,
<4D6963726F736F667420576F7264202D20A4D5A46CA1D0A740A4E5A5FEB6B02E646F63>
我 讀 孔 子 ( 第 六 屆 ) 征 文 比 賽 獲 獎 作 文 選 集 澳 門 人 文 科 學 學 會 主 辦 澳 門 基 金 會 教 育 暨 青 年 局 贊 助 2008 11 1 一 等 獎 ( 以 下 以 下 按 照 學 校 筆 劃 順 序 排 列 ) 將 心 比 心, 推 己 及 人 王 錦 江 ( 培 正 中 學 ) 己 所 不 欲, 勿 施 於 人 聖 人 孔 子 這 句 只 有 八
untitled
1 7 7.1 7.2 7.3 7.4 7.5 2 7.1 VFT virtual 7.1 3 1 1. 2. public protected public 3. VFT 4. this const volatile 4 2 5. ( ) ( ) 7.1 6. no-static virtual 7.2 7. inline 7.3 5 3 8. this this 9. ( ) ( ) delete
科学计算的语言-FORTRAN95
科 学 计 算 的 语 言 -FORTRAN95 目 录 第 一 篇 闲 话 第 1 章 目 的 是 计 算 第 2 章 FORTRAN95 如 何 描 述 计 算 第 3 章 FORTRAN 的 编 译 系 统 第 二 篇 计 算 的 叙 述 第 4 章 FORTRAN95 语 言 的 形 貌 第 5 章 准 备 数 据 第 6 章 构 造 数 据 第 7 章 声 明 数 据 第 8 章 构 造
1 4 1.1 4 1.2..4 2..4 2.1..4 3.4 3.1 Java.5 3.1.1..5 3.1.2 5 3.1.3 6 4.6 4.1 6 4.2.6 5 7 5.1..8 5.1.1 8 5.1.2..8 5.1.3..8 5.1.4..9 5.2..9 6.10 6.1.10
Java V1.0.1 2007 4 10 1 4 1.1 4 1.2..4 2..4 2.1..4 3.4 3.1 Java.5 3.1.1..5 3.1.2 5 3.1.3 6 4.6 4.1 6 4.2.6 5 7 5.1..8 5.1.1 8 5.1.2..8 5.1.3..8 5.1.4..9 5.2..9 6.10 6.1.10 6.2.10 6.3..10 6.4 11 7.12 7.1
理 L~ 胆 有 纪 嚣 中 国 共 产 党 早 期 的 主 要 领 导 人, 伟 大 的 马 克 思 主 义 者, 卓 越 的 无 产 阶 级 革 命 家 理 论 家 和 宣 传 家, 中 国 革 命 文 学 事 业 的 重 要 奠 基 人 一 一 瞿 秋 白 同 志 诞 辰 110 周 年 暨
陈 铁 健, 却 因 为 多 余 的 话 一 度 被 误 为 多 余 的 人 著 品 理 L~ 胆 有 纪 嚣 中 国 共 产 党 早 期 的 主 要 领 导 人, 伟 大 的 马 克 思 主 义 者, 卓 越 的 无 产 阶 级 革 命 家 理 论 家 和 宣 传 家, 中 国 革 命 文 学 事 业 的 重 要 奠 基 人 一 一 瞿 秋 白 同 志 诞 辰 110 周 年 暨 伟 大 的 五
Microsoft Word - 97.01.30軟體設計第二部份範例試題_C++_ _1_.doc
電 腦 軟 體 設 計 乙 級 技 術 士 技 能 檢 定 術 科 測 試 範 例 試 題 (C++) 試 題 編 號 :11900-920201-4 審 定 日 期 : 94 年 7 月 1 日 修 訂 日 期 : 96 年 2 月 1 日 97 年 1 月 30 日 ( 第 二 部 份 ) 電 腦 軟 體 設 計 乙 級 技 術 士 技 能 檢 定 術 科 測 試 應 檢 參 考 資 料 壹 試
第3章.doc
3 3 3 3.1 3 IT Trend C++ Java SAP Advantech ERPCRM C++ C++ Synopsys C++ NEC C C++PHP C++Java C++Java VIA C++ 3COM C++ SPSS C++ Sybase C++LinuxUNIX Motorola C++ IBM C++Java Oracle Java HP C++ C++ Yahoo
untitled
MODBUS 1 MODBUS...1 1...4 1.1...4 1.2...4 1.3...4 1.4... 2...5 2.1...5 2.2...5 3...6 3.1 OPENSERIAL...6 3.2 CLOSESERIAL...8 3.3 RDMULTIBIT...8 3.4 RDMULTIWORD...9 3.5 WRTONEBIT...11 3.6 WRTONEWORD...12
.' 6! "! 6 "'' 6 7% $! 7%/'& 人 类 非 洲 锥 虫 病 又 称 昏 睡 病 是 布 氏 锥 虫 冈 比 亚 亚 种!! 或 布 氏 锥 虫 罗 得 西 亚 种 "#$$ %! &'!!! 感 染 引 起 的 一 种 寄 生 虫 病 以 采 采 蝇! 为 传 播 ' 媒
) 文 章 编 号 '.')) 论 著!"#$%&' ' ' ' ' '!"# ' $%& ' ' '8 目 的 对 ' 例 输 入 性 非 洲 锥 虫 病 患 者 进 行 实 验 室 诊 断 与 病 原 体 鉴 定 方 法 收 集 患 者 的 临 床 发 病 与 流 行 病 学 调 查 资 料 采 集 血 样 脑 脊 液 瑞 氏 吉 氏 染 色 涂 片 后 镜 检 用 布 氏 锥 虫 表 达 位
Windows RTEMS 1 Danilliu MMI TCP/IP QEMU i386 QEMU ARM POWERPC i386 IPC PC104 uc/os-ii uc/os MMI TCP/IP i386 PORT Linux ecos Linux ecos ecos eco
Windows RTEMS 1 Danilliu MMI TCP/IP 80486 QEMU i386 QEMU ARM POWERPC i386 IPC PC104 uc/os-ii uc/os MMI TCP/IP i386 PORT Linux ecos Linux ecos ecos ecos Email www.rtems.com RTEMS ecos RTEMS RTEMS Windows
Microsoft PowerPoint - plan06.ppt
程 序 设 计 语 言 原 理 Principle of Programming Languages 裘 宗 燕 北 京 大 学 数 学 学 院 2012.2~2012.6 6. 基 本 控 制 抽 象 子 程 序 抽 象 子 程 序 活 动 和 局 部 环 境 静 态 实 现 模 型 一 般 实 现 模 型 调 用 序 列 和 在 线 展 开 参 数 机 制 泛 型 子 程 序 异 常 处 理 其
untitled
不 料 料 例 : ( 料 ) 串 度 8 年 數 串 度 4 串 度 數 數 9- ( ) 利 數 struct { ; ; 數 struct 數 ; 9-2 數 利 數 C struct 數 ; C++ 數 ; struct 省略 9-3 例 ( 料 例 ) struct people{ char name[]; int age; char address[4]; char phone[]; int
(2) 廠 商 具 有 維 修 維 護 或 售 後 服 務 能 力 之 證 明 ;(3) 廠 商 具 有 製 造 供 應 或 承 做 能 力 之 證 明 ;(4) 具 有 相 當 人 力 之 證 明 屬 特 定 資 格 之 ㄧ 8.(3) 機 關 辦 理 預 算 金 額 為 新 台 幣 四 億 元
政 府 採 購 法 規 概 要 題 庫 最 後 更 新 日 期 :( 人 發 局 第 一 期 ) 2010/03/20 選 擇 題 : ( 答 案 ) 正 確 錯 誤 解 析 1.(3) 機 關 訂 定 招 標 文 件, 何 者 正 確?(1) 廠 商 履 行 契 約 所 必 須 具 備 之 財 務 商 業 或 技 術 資 格 條 件, 不 考 慮 廠 商 在 外 國 之 商 業 活 動 應 (2)
untitled
MPICH [email protected] 1 MPICH for Microsoft Windows 1.1 MPICH for Microsoft Windows Windows NT4/2000/XP Professional Server Windows 95/98 TCP/IP MPICH MS VC++ 6.x MS VC++.NET Compaq Visual Fortran 6.x
口 的 70% 连 南 县 的 瑶 族. 有 排 瑶 过 山 瑶 排 瑶 6 万 多 人 住 在 三 排 南 岗 i 雨 水 大 麦 山 大 坪 香 坪 盘 石 金 坑 8 个 乡 镇. 形 成 了 占 全 县 面 积 80% 的 聚 居 地 << 连 州 志 } 卷 八 排 瑶 志 曰 在 连 者
居 住 地 域 与 文 化 变 迁 一 一 以 广 东 瑶 族 为 例 赵 家 旺 * 中 国 是 个 多 民 族 国 家. 共 有 56 个 民 族. 其 中 少 数 民 族 有 归 个 根 据 1990 年 的 人 口 普 查. 全 国 总 人 口 11 亿 3 千 多 万 人. 汉 族 10 忆 4 千 多 万 人. 占 全 国 总 人 口 的 90% 多. 少 数 民 族 人 口 不 到 10%
Microsoft Word - 把时间当作朋友(2011第3版)3.0.b.07.doc
2 5 8 11 0 1. 13 2. 15 3. 18 1 1. 22 2. 25 3. 27 2 1. 35 2. 38 3. 41 4. 43 5. 48 6. 50 3 1. 56 2. 59 3. 63 4. 65 5. 69 13 22 35 56 6. 74 7. 82 8. 84 9. 87 10. 97 11. 102 12. 107 13. 111 4 114 1. 114 2.
C C C The Most Beautiful Language and Most Dangerous Language in the Programming World! C 2 C C C 4 C 40 30 10 Project 30 C Project 3 60 Project 40
C C [email protected] C C C C The Most Beautiful Language and Most Dangerous Language in the Programming World! C 2 C C C 4 C 40 30 10 Project 30 C Project 3 60 Project 40 Week3 C Week5 Week5 Memory & Pointer
CC213
: (Ken-Yi Lee), E-mail: [email protected] 9 [P.11] : Dev C++ [P.12] : http://c.feis.tw [P.13] [P.14] [P.15] [P.17] [P.23] Dev C++ [P.24] [P.27] [P.34] C / C++ [P.35] 10 C / C++ C C++ C C++ C++ C ( ) C++
epub83-1
C++Builder 1 C + + B u i l d e r C + + B u i l d e r C + + B u i l d e r C + + B u i l d e r 1.1 1.1.1 1-1 1. 1-1 1 2. 1-1 2 A c c e s s P a r a d o x Visual FoxPro 3. / C / S 2 C + + B u i l d e r / C
<4D6963726F736F667420576F7264202D20B2C4A4BBA9A1B8EAB054BAD8A46C2DB773BB44B443C5E9B27BAA70B56FAE69BB50A5BCA8D3B773C1CDB6D5BDD2ABE1A4DFB16F>
課 程 時 間 :98 年 5 月 2 日 ( 六 ) 課 程 名 稱 : 新 聞 媒 體 現 況 發 展 與 未 來 新 趨 勢 課 程 講 師 : 陳 佩 敏 老 師 中 天 電 視 公 司 新 聞 部 製 播 中 心 主 任 6 th 資 訊 種 子 學 員 心 得 : 整 理 人 :6 th 課 務 程 仲 駿 (0968-471656) 第 一 組 姓 名 蘇 怡 萍 學 校 / 系 別
ebook8-30
3 0 C C C C C C++ C + + C++ GNU C/C++ GNU egcs UNIX shell s h e l l g a w k P e r l U N I X I / O UNIX shell awk P e r l U N I X C C C C C C U N I X 30.1 C C U N I X 70 C C U N I X U N I X U N I X C Dennis
BOOL EnumWindows(WNDENUMPROC lparam); lpenumfunc, LPARAM (Native Interface) PowerBuilder PowerBuilder PBNI 2
PowerBuilder 9 PowerBuilder Native Interface(PBNI) PowerBuilder 9 PowerBuilder C++ Java PowerBuilder 9 PBNI PowerBuilder Java C++ PowerBuilder NVO / PowerBuilder C/C++ PowerBuilder 9.0 PowerBuilder Native
幻灯片 1
白 色 花 诗 集 人 民 文 学 出 版 社 1981 年 出 版 共 收 七 月 派 诗 人 阿 垅 鲁 藜 孙 钿 彭 燕 郊 方 然 冀 汸 钟 瑄 郑 思 曾 卓 杜 谷 绿 原 胡 征 芦 甸 徐 放 牛 汉 鲁 煤 化 铁 朱 健 朱 谷 怀 罗 洛 等 二 十 人 的 诗 作 一 百 十 九 首 集 名 出 自 阿 垅 未 入 选 的 一 首 诗 中 要 开 作 一 枝 白 色 花
ebook50-15
15 82 C / C + + Developer Studio M F C C C + + 83 C / C + + M F C D L L D L L 84 M F C MFC DLL M F C 85 MFC DLL 15.1 82 C/C++ C C + + D L L M F C M F C 84 Developer Studio S t u d i o 292 C _ c p l u s
1 LINUX IDE Emacs gcc gdb Emacs + gcc + gdb IDE Emacs IDE C Emacs Emacs IDE ICE Integrated Computing Environment Emacs Unix Linux Emacs Emacs Emacs Un
Linux C July 27, 2016 Contents 1 Linux IDE 1 2 GCC 3 2.1 hello.c hello.exe........................... 5 2.2............................... 9 2.2.1 -Wall................................ 9 2.2.2 -E..................................
Chapter 9: Objects and Classes
Fortran Algol Pascal Modula-2 BCPL C Simula SmallTalk C++ Ada Java C# C Fortran 5.1 message A B 5.2 1 class Vehicle subclass Car object mycar public class Vehicle extends Object{ public int WheelNum
VB程序设计教程
高 等 学 校 教 材 Visual Basic 程 序 设 计 教 程 魏 东 平 郑 立 垠 梁 玉 环 石 油 大 学 出 版 社 内 容 提 要 本 书 是 按 高 等 学 校 计 算 机 程 序 设 计 课 程 教 学 大 纲 编 写 的 大 学 教 材, 主 要 包 括 VB 基 础 知 识 常 用 程 序 结 构 和 算 法 Windows 用 户 界 面 设 计 基 础 文 件 处
