第七讲 继承与多态



Similar documents
Chapter12 Derived Classes

c_cpp

Strings

Microsoft PowerPoint - L17_Inheritance_v4.pptx

untitled

extend

FY.DOC

untitled

Strings

Microsoft Word - chap10.doc

第3章.doc

但 洋 糖 最 终 乘 船 溯 江 而 上, 再 加 上 民 国 初 年 至 抗 战 前 夕 二 十 余 年 间, 四 川 接 连 不 断 遭 受 水 灾 旱 灾 地 震, 平 均 每 月 爆 发 两 次 军 阀 混 战, 乡 村 遭 受 极 大 破 坏,( 赵 泉 民,2007) 农 村 经 济

提问袁小兵:

2013 C 1 # include <stdio.h> 2 int main ( void ) 3 { 4 int cases, a, b, i; 5 scanf ("%d", & cases ); 6 for (i = 0;i < cases ;i ++) 7 { 8 scanf ("%d %d

C 1 # include <stdio.h> 2 int main ( void ) { 4 int cases, i; 5 long long a, b; 6 scanf ("%d", & cases ); 7 for (i = 0;i < cases ;i ++) 8 { 9

Microsoft Word cppFinalSolution.doc

新版 明解C++入門編

口 的 70% 连 南 县 的 瑶 族. 有 排 瑶 过 山 瑶 排 瑶 6 万 多 人 住 在 三 排 南 岗 i 雨 水 大 麦 山 大 坪 香 坪 盘 石 金 坑 8 个 乡 镇. 形 成 了 占 全 县 面 积 80% 的 聚 居 地 << 连 州 志 } 卷 八 排 瑶 志 曰 在 连 者


6寸PDF生成工具

Microsoft Word - ch04三校.doc

C/C++语言 - C/C++数据

untitled

(6) 要 求 付 款 管 理 员 从 预 订 表 中 查 询 距 预 订 的 会 议 时 间 两 周 内 的 预 定, 根 据 客 户 记 录 给 满 足 条 件 的 客 户 发 送 支 付 余 款 要 求 (7) 支 付 余 款 管 理 员 收 到 客 户 余 款 支 付 的 通 知 后, 检

C/C++程序设计 - 字符串与格式化输入/输出

02所有分支机构的营业场所和电话.xls


小班上学期课程

<4D F736F F F696E74202D20332D322E432B2BC3E6CFF2B6D4CFF3B3CCD0F2C9E8BCC6A1AAD6D8D4D8A1A2BCCCB3D0A1A2B6E0CCACBACDBEDBBACF2E707074>

全国计算机技术与软件专业技术资格(水平)考试

MXDX.s10

Microsoft Word - 物件導向編程精要.doc

_題目卷

<4D F736F F D20A4D5A46CA1D0A740A4E5A5FEB6B02E646F63>

目 前 言... 1 一 发 展 背 景... 2 ( 一 ) 发 展 优 势...2 ( 二 ) 机 遇 挑 战...6 ( 三 ) 战 略 意 义...8 二 总 体 要 求... 9 ( 一 ) 指 导 思 想...9 ( 二 ) 基 本 原 则...10 ( 三 ) 战 略 定 位... 1

<4D F736F F D20C6C0BCB6B1A8B8E6B7E2C3E6A3A8C8F0B0B2B9FACDB6B8FAD7D9A3A9>

相 应 功 能 (5) 再 将 Boy 类 作 为 Girl 类 的 友 元 类, 在 Boy 类 的 某 成 员 函 数 VisitGirl(Girl & ) 中 访 问 Girl 类 的 私 有 成 员, 观 察 编 译 器 给 出 的 信 息 ( 6 ) 删 除 两 个 类 中 的 函 数 V

Microsoft Word - d.doc

untitled

消 费 特 征 贸 易 对 象 客 户 群 体 跨 境 电 商 出 口 占 据 绝 对 比 重, 进 口 增 长 迅 速 出 口 端, 美 国 和 欧 盟 市 场 较 为 稳 定, 东 盟 等 群 体 增 长 迅 速 ; 进 口 端 以 日 本 韩 国 新 西 兰 等 发 达 国 家 为 主 主 要

<4D F736F F D20C6C0BCB6B1A8B8E6B7E2C3E6A3A83135C4EAB6C8B4CEBCB6D5AEC8AFB6ABDDB8D6A4C8AFB8FAD7D9A3A9>

中国管理科学 年 -- 及其价 差 偏 离 程 度被 广 泛 应 用 于 配 对 策 略 构 造 ) 欧式距离以距离最 小 为 依 据 构 建 最 佳 配 对 交 易 组 合以避免同一 股 票 同 时 被 买 入 和 卖 空 的 风 险 在 例如 将协整配对法应 V ) W0)I 0等

Microsoft Word - 博弈圣经

目 录 1 国 务 院 中 央 军 委 关 于 建 立 和 完 善 军 民 结 合 寓 军 于 民 武 器 装 备 科 研 生 产 体 系 的 若 干 意 见 2 国 务 院 关 于 鼓 励 和 引 导 民 间 投 资 健 康 发 展 的 若 干 意 见 >> 国 防 科 工

Microsoft Word - 01.DOC




<4D F736F F F696E74202D ABE1A4A420A4A4C2E5BEC7B7A7BDD720C2E5BEC7B7BDAC79BB50B56FAE6920ADD9B0B7AFE82E BACDBAE65BCD2A6A15D>

从 因 人 设 事 谈 起 一 部 文 学 作 品 ( 尤 其 是 长 篇 小 说 ) 的 结 构 至 关 重 要, 因 为 它 是 文 本 整 体 的 组 织 方 式 和 内 部 构 造, 既 是 形 式 又 是 内 容 ; 乃 是 表 达 主 题 最 有 效 的 艺 术 手 段 元 代 戏 曲

循经指压疗法

Microsoft Word - HERBRECIPES《中國藥膳》.doc

毛主席的猪

untitled

流基地领导小组


附件1.FIT)

北魏山东佛教文化个案研究

ebook55-13

# $% & # # # ( ) $* # # # + # # # # # # # % #, # # #, # # # # # # # # # # # # # # # % $ # #, #, #, # # # #,,,, # # # # # # # # # # # # # # # # # %, #

1911 年 武 汉 起 义, 广 东 独 立 胡 汉 民 任 总 督, 陈 任 广 东 军 政 府 外 交 部 副 部 长 陈 不 愿 做 官, 几 个 月 后 即 辞 职 1915 年 与 李 煜 堂 设 立 上 海 保 险 公 司, 陈 任 主 席 1921 年 孙 中 山 就 任 非 常 大

得 到 了 補 償. 對 於 武 姜 而 言, 莊 公 與 自 己 的 關 係 並 不 親 密, 而 共 叔 段 又 是 自 己 向 來 疼 愛 有 加 的 兒 子, 所 以, 對 莊 公 提 出 再 怎 麼 無 理 的 要 求, 武 姜 也 不 會 覺 得 有 什 麼 不 妥 之 處, 而 對 共

新・解きながら学ぶJava

<4D F736F F D C4EAB9FABCD2B9ABCEF1D4B1D0D0D5FEC4DCC1A6B2E2D1E9A3A841C0E0A3A92E646F63>

第 一 部 分 广 州 大 学 概 况 一 广 州 大 学 主 要 职 能 ( 一 ) 广 州 大 学 是 2000 年 4 月 经 教 育 部 批 准, 由 广 州 师 范 学 院 华 南 建 设 学 院 ( 西 院 ) 广 州 教 育 学 院 原 广 州 大 学 和 广 州 高 等 师 范 专

C++ 程序设计 告别 OJ2 - 参考答案 MASTER 2019 年 5 月 3 日 1

一 耀 州 青 瓷 的 裝 飾 手 法 與 紋 飾 種 類 耀 州 窯 的 裝 飾 紋 樣, 豐 富 多 變, 而 且 題 材 內 容 廣 泛, 組 合 形 式 多 樣, 圖 案 形 象 優 美, 令 人 賞 心 悅 目, 並 且 反 映 了 當 時 社 會 的 審 美 趣 味 和 理 想 裝 飾

2 政策版 教育部為勗勉軍訓教官落實 育署及大專校院之各分區國防 軍訓工作抱持之高度熱忱 在 102學年度全國績優軍訓教官選拔獲獎名單 高中職組 學生服務及戮力於校園安全維 教育及資源中心完成初審後 校園安全 學生生活輔導及防 護之辛勞 特辦理 102學年 送本部學生事務及特殊教育司 制學生藥物濫用

Microsoft PowerPoint - ch_12 [唯讀]

工 序 的 是 ( ) A. 卷 筒 切 筒 装 药 造 粒 B. 搬 运 造 粒 切 引 装 药 C. 造 粒 切 引 包 装 检 验 D. 切 引 包 装 检 验 运 输 7. 甲 公 司 将 其 实 施 工 项 目 发 包 给 乙 公 司, 乙 公 司 将 其 中 部 分 业 务 分 包 给

试卷

untitled

Microsoft Word - 把时间当作朋友(2011第3版)3.0.b.06.doc

商学院团委学生会 团委书记兼学生会指导老师 孙永义 团委副书记 刘 伟 学生会主席 曹 亮 团委秘书长兼学生会副主席 乔 爽 秘书处 孔维雪 王 峰 郭雅薇 宣传部 赵 淼 李 翔 李程瑶 外联部 邹秋博 周 磊 张哲浩 学研部 刘宇童 刘润龙 魏彬彬 组织部 林立杰 谭兴全 肖雁冰 体育部 郭忠海

Microsoft Word - CPE考生使用手冊 docx


<4D F736F F D F F31375F312D31B7A2D0D0B9C9B7DDBCB0D6A7B8B6CFD6BDF0B9BAC2F2D7CAB2FAB2A2C4BCBCAFC5E4CCD7D7CABDF0F4DFB9D8C1AABDBBD2D7B1A8B8E6CAE9A3A8B2DDB0B8A3A92E646F63>

1 住 房 保 障 10BA 住 房 保 障 索 引 号 : / 主 题 名 称 : 住 房 保 障 发 文 单 位 : 中 华 人 民 共 和 国 住 房 和 城 乡 建 发 文 日 期 : , 中 华 人 民 共 和 国 民 政 部, 中

C++ 程序设计 告别 OJ1 - 参考答案 MASTER 2019 年 5 月 3 日 1

****************

<4D F736F F D20B8F2A6B1BEA4B1D3BEC7BE69A5CDB4BCBC7AA4A7B6C0ABD2A4BAB8672E646F63>

「行政院及所屬各機關出國報告綜合處理要點」

<4D F736F F D20D0A1CBB5BCAFA1B6B9ABBCA6B5C4D4A2D1D4A1B7A3A8BCADD2BBA3A92E646F63>

《河殇》

<4D F736F F D20A4A4C1FAC3E4BBDAA448C3E4A677AF50BB50C452A5BDAC46A7BD>

中国教育管理全集_二十五_

6寸PDF生成工具

目 录 禁 令 一 览 中 央 八 项 规 定 5 中 央 六 项 禁 令 6 关 于 在 全 国 纪 检 监 察 系 统 开 展 会 员 卡 专 项 清 退 活 动 的 通 知 中 央 纪 委 监 察 部 7 关 于 党 政 机 关 停 止 新 建 楼 堂 馆 所 和 清 理 办 公 用 房 的

授权发布:中华人民共和国国民经济和社会发展第十二个五年规划纲要

Microsoft Word - 中國文學.doc


馬太福音 劉梅蕾師母

第十章 中国传统节日与礼俗(22900)

通 过 这 例 子, 可 以 理 解 处 方 用 药 的 大 法, 并 能 看 到 几 个 问 题 首 先 是 处 方 根 据 治 法, 有 一 定 的 方 向 和 范 围, 针 对 病 因 病 垃 和 症 状 三 方 面 用 药, 应 该 互 相 呼 应 如 前 胡 祛 风 寒, 又 能 降 气

地产研究周刊 2014年 第二十六期

平 安 也 不 是 用 金 钱 可 以 买 到 的 我 们 的 俗 语 说," 平 安 即 是 福 " 人 们 都 喜 爱 平 安, 寻 求 平 安, 但 有 几 个 人 真 得 着 了 平 安 呢? 有 几 个 人 家 庭 中 洽 洽 融 融, 没 有 争 吵, 没 有 口 角, 父 慈 子 孝,

莫 奈 日 出 印 象 睡 莲 蒋 芷 若 画 家 简 介 克 劳 德 莫 奈, 法 国 画 家, 被 誉 为 印 象 派 之 父, 是 印 象 派 代 表 人 物 和 创 始 人 之 一 莫 奈 是 法 国 最 重 要 的 画 家 之 一, 印 象 派 的 理 论 和 实 践 大 部 分 都 有

<4D F736F F D20A4BAC363B0EAA4A4AC71A6D2C075A87DA740A4E5A8E5C2C3A740AB7EB6B03938A FA7B9BD5A2E646F63>

2013考研必备资料:

15 大 豐 痛 炎 好 膠 囊 500 毫 克 衛 署 藥 製 字 第 號 " 大 豐 " 痛 炎 好 錠 250 公 絲 衛 署 藥 製 字 第 號 17 " 大 豐

中央一号文件

Transcription:

第 七 章 继 承 与 派 生 1

本 章 主 要 内 容 的 继 承 成 员 的 访 问 控 制 单 继 承 与 多 继 承 派 生 的 构 造 析 构 函 数 成 员 的 标 识 与 访 问 深 度 探 索 2

的 继 承 与 派 生 的 继 承 与 派 生 保 持 已 有 的 特 性 而 构 造 新 的 过 程 称 为 继 承 在 已 有 的 基 础 上 新 增 自 己 的 特 性 而 产 生 新 的 过 程 称 为 派 生 被 继 承 的 已 有 称 为 基 ( 或 父 ) 派 生 出 的 新 称 为 派 生 ( 或 子 ) 3

的 继 承 与 派 生 继 承 与 派 生 问 题 举 例 交 通 工 具 汽 车 小 汽 车 卡 车 旅 行 车 工 具 车 轿 车 面 包 车 4

的 继 承 与 派 生 继 承 与 派 生 问 题 举 例 猴 子 动 物 猫 科 鸟 狮 子 虎 猎 豹 5

的 继 承 与 派 生 继 承 与 派 生 问 题 举 例 几 何 形 状 圆 矩 形 6

的 继 承 与 派 生 继 承 与 派 生 问 题 举 例 兼 职 技 术 人 员 雇 员 管 理 人 员 销 售 人 员 销 售 经 理 7

的 继 承 与 派 生 的 层 次 结 构 由 上 到 下, 是 一 个 具 体 化 特 殊 化 的 过 程 由 下 到 上, 是 一 个 抽 象 化 的 过 程 8

的 继 承 与 派 生 继 承 与 派 生 的 目 的 继 承 的 目 的 : 实 现 代 码 重 用 派 生 的 目 的 : 当 新 的 问 题 出 现, 原 有 程 序 无 法 解 决 ( 或 不 能 完 全 解 决 ) 时, 需 要 对 原 有 程 序 进 行 改 造, 实 现 代 码 扩 充 9

的 继 承 与 派 生 派 生 新 的 过 程 吸 收 基 成 员 基 的 全 部 数 据 成 员 和 除 了 构 造 析 构 函 数 外 的 全 部 函 数 成 员 改 造 基 成 员 基 成 员 的 访 问 控 制 对 基 数 据 或 函 数 成 员 的 隐 藏 添 加 新 的 成 员 一 般 成 员 的 添 加 构 造 函 数 和 析 构 函 数 10

的 继 承 与 派 生 派 生 的 声 明 class 派 生 名 : 继 承 方 式 基 名 { 派 生 成 员 声 明 ; 11

成 员 的 访 问 控 制 继 承 方 式 不 同 继 承 方 式 的 影 响 主 要 体 现 在 : 派 生 成 员 对 基 成 员 的 访 问 权 限 通 过 派 生 对 象 对 基 成 员 的 访 问 权 限 三 种 继 承 方 式 公 有 继 承 私 有 继 承, 默 认 保 护 继 承 12

成 员 的 访 问 控 制 公 有 继 承 (public) 基 的 public 和 protected 成 员 的 访 问 属 性 在 派 生 中 保 持 不 变, 但 基 的 private 成 员 不 可 直 接 访 问 派 生 中 的 成 员 函 数 可 以 直 接 访 问 基 中 的 public 和 protected 成 员, 但 不 能 直 接 访 问 基 的 private 成 员 通 过 派 生 的 对 象 只 能 访 问 基 的 public 成 员 13

成 员 的 访 问 控 制 例 7-1 公 有 继 承 举 例 class Point { // 基 Point 的 定 义 public: // 公 有 函 数 成 员 void initpoint(float x = 0, float y = 0) { this->x = x; this->y = y;} void move(float offx, float offy) { x += offx; y += offy; } float getx() const { return x; } float gety() const { return y; } private: // 私 有 数 据 成 员 float x, y; 14

class Rectangle: public Point { // 派 生 定 义 部 分 public: // 新 增 公 有 函 数 成 员 void initrectangle(float x, float y, float w, float h) { initpoint(x, y); // 调 用 基 公 有 成 员 函 数 this->w = w; this->h = h; } float geth() const { return h; } float getw() const { return w; } private: // 新 增 私 有 数 据 成 员 float w, h; 15

#include <iostream> #include <cmath> using namespace std; int main() { Rectangle rect; // 定 义 Rectangle 的 对 象 // 设 置 矩 形 的 数 据 rect.initrectangle(2, 3, 20, 10); rect.move(3,2); // 移 动 矩 形 位 置 cout << "The data of rect(x,y,w,h): " << endl; // 输 出 矩 形 的 特 征 参 数 cout << rect.getx() <<", " << rect.gety() << ", " << rect.getw() << ", " << rect.geth() << endl; return 0; } 16

成 员 的 访 问 控 制 私 有 继 承 (private) 基 的 public 和 protected 成 员 都 以 private 身 份 出 现 在 派 生 中, 但 基 的 private 成 员 不 可 直 接 访 问 派 生 中 的 成 员 函 数 可 以 直 接 访 问 基 中 的 public 和 protected 成 员, 但 不 能 直 接 访 问 基 的 private 成 员 通 过 派 生 的 对 象 不 能 直 接 访 问 基 中 的 任 何 成 员 17

成 员 的 访 问 控 制 例 7-2 私 有 继 承 举 例 class Rectangle: private Point { // 派 生 定 义 部 分 public:// 新 增 公 有 函 数 成 员 void initrectangle(float x, float y, float w, float h) { initpoint(x, y); // 调 用 基 公 有 成 员 函 数 this->w = w; this->h = h; } void move(float offx, float offy) { Point::move(offX, offy); } float getx() const { return Point::getX(); } float gety() const { return Point::getY(); } float geth() const { return h; } float getw() const { return w; } private: // 新 增 私 有 数 据 成 员 float w, h; 18

#include <iostream> #include <cmath> using namespace std; int main() { Rectangle rect; // 定 义 Rectangle 的 对 象 rect.initrectangle(2, 3, 20, 10); // 设 置 矩 形 的 数 据 rect.move(3,2); // 移 动 矩 形 位 置 cout << "The data of rect(x,y,w,h): " << endl; cout << rect.getx() <<", " // 输 出 矩 形 的 特 征 参 数 << rect.gety() << ", " << rect.getw() << ", " << rect.geth() << endl; return 0; } 19

成 员 的 访 问 控 制 保 护 继 承 (protected) 基 的 public 和 protected 成 员 都 以 protected 身 份 出 现 在 派 生 中, 但 基 的 private 成 员 不 可 直 接 访 问 派 生 中 的 成 员 函 数 可 以 直 接 访 问 基 中 的 public 和 protected 成 员, 但 不 能 直 接 访 问 基 的 private 成 员 通 过 派 生 的 对 象 不 能 直 接 访 问 基 中 的 任 何 成 员 20

成 员 的 访 问 控 制 protected 成 员 的 特 点 与 作 用 对 建 立 其 所 在 对 象 的 模 块 来 说, 它 与 private 成 员 的 性 质 相 同 对 于 其 派 生 来 说, 它 与 public 成 员 的 性 质 相 同 既 实 现 了 数 据 隐 藏, 又 方 便 继 承, 实 现 代 码 重 用 21

成 员 的 访 问 控 制 例 protected 成 员 举 例 class A { protected: int x; int main() { } A a; a.x = 5; // 错 误 22

class A { protected: int x; class B: public A{ public: void function(); void B:function() { x = 5; // 正 确 } 23

型 兼 容 规 则 型 兼 容 一 个 公 有 派 生 的 对 象 在 使 用 上 可 以 被 当 作 基 的 对 象, 反 之 则 禁 止 具 体 表 现 在 : 派 生 的 对 象 可 以 隐 含 转 换 为 基 对 象 派 生 的 对 象 可 以 初 始 化 基 的 引 用 派 生 的 指 针 可 以 隐 含 转 换 为 基 的 指 针 通 过 基 对 象 名 指 针 只 能 使 用 从 基 继 承 的 成 员 24

例 7-3 型 兼 容 规 则 举 例 型 兼 容 //7_3.cpp #include <iostream> using namespace std; class Base1 { // 基 Base1 定 义 public: void display() const { cout << "Base1::display()" << endl; } 25

class Base2: public Base1 { // 公 有 派 生 Base2 定 义 public: void display() const { cout << "Base2::display()" << endl; } class Derived: public Base2 { // 公 有 派 生 Derived 定 义 public: void display() const { cout << "Derived::display()" << endl; } void fun(base1 *ptr) { // 参 数 为 指 向 基 对 象 的 指 针 ptr->display(); //" 对 象 指 针 -> 成 员 名 " } 26

int main() { // 主 函 数 Base1 base1; // 声 明 Base1 对 象 Base2 base2; // 声 明 Base2 对 象 Derived derived; // 声 明 Derived 对 象 // 用 Base1 对 象 的 指 针 调 用 fun 函 数 fun(&base1); // 用 Base2 对 象 的 指 针 调 用 fun 函 数 fun(&base2); // 用 Derived 对 象 的 指 针 调 用 fun 函 数 fun(&derived); } return 0; 运 行 结 果 : Base1::display() Base1 ::display() Base1 ::display() 27

单 继 承 与 多 继 承 基 与 派 生 的 对 应 关 系 单 继 承 派 生 只 从 一 个 基 派 生 多 继 承 派 生 从 多 个 基 派 生 多 重 派 生 由 一 个 基 派 生 出 多 个 不 同 的 派 生 多 层 派 生 派 生 又 作 为 基, 继 续 派 生 新 的 28

单 继 承 与 多 继 承 多 继 承 时 派 生 的 声 明 class 派 生 名 : 继 承 方 式 1 基 名 1, 继 承 方 式 2 基 名 2, { 派 生 成 员 声 明 ; 注 意 : 每 一 个 继 承 方 式, 只 用 于 限 制 对 紧 随 其 后 之 基 的 继 承 29

单 继 承 与 多 继 承 多 继 承 举 例 class A { public: void seta(int); void showa() const; private: int a; class B { public: void setb(int); void showb() const; private: int b; class C : public A, private B { public: void setc(int, int, int); void showc() const; private const: int c; 30

void A::setA(int x) { } a=x; void B::setB(int x) { } b=x; void C::setC(int x, int y, int z) { } // 派 生 成 员 直 接 访 问 基 的 // 公 有 成 员 seta(x); setb(y); c = z; // 其 他 函 数 实 现 略 int main() { C obj; obj.seta(5); obj.showa(); obj.setc(6,7,9); obj.showc(); // obj.setb(6); 错 误 // obj.showb(); 错 误 return 0; } 31

派 生 的 构 造 析 构 函 数 继 承 时 的 构 造 函 数 基 的 构 造 函 数 不 被 继 承, 派 生 中 需 要 声 明 自 己 的 构 造 函 数 定 义 构 造 函 数 时, 只 需 要 对 本 中 新 增 成 员 进 行 初 始 化, 对 继 承 来 的 基 成 员 的 初 始 化, 自 动 调 用 基 构 造 函 数 完 成 派 生 的 构 造 函 数 需 要 给 基 的 构 造 函 数 传 递 参 数 32

派 生 的 构 造 析 构 函 数 单 一 继 承 时 的 构 造 函 数 派 生 名 :: 派 生 名 ( 参 数 表 ) : 基 名 ( 基 初 始 化 参 数 表 ), 成 员 对 象 名 1( 成 员 对 象 1 初 始 化 参 数 表 ),, 成 员 对 象 名 m( 成 员 对 象 m 初 始 化 参 数 表 ) { 其 他 初 始 化 操 作 ; 33

派 生 的 构 造 析 构 函 数 单 一 继 承 时 的 构 造 函 数 举 例 #include<iostream> using namecpace std; class B { public: B(); B(int i); ~B(); void print() const; private: int b; 34

B::B() { b=0; cout << "B's default constructor called." << endl; } B::B(int i) { b=i; cout << "B's constructor called." << endl; } B::~B() { cout << "B's destructor called." << endl; } void B::print() const { cout << b << endl; } 35

class C: public B { public: C(); C(int i, int j); ~C(); void print() const; private: int c; 36

C::C() { c = 0; cout << "C's default constructor called." << endl; } C::C(int i,int j): B(i) { c = j; cout << "C's constructor called." << endl; } C::~C() { cout << "C's destructor called." << endl; } void C::print() const { B::print(); cout << c << endl; } int main() { C obj(5, 6); obj.print(); return 0; } 37

派 生 的 构 造 析 构 函 数 多 继 承 时 的 构 造 函 数 派 生 名 :: 派 生 名 ( 参 数 表 ) : 基 名 1( 基 1 初 始 化 参 数 表 ), 基 名 2( 基 2 初 始 化 参 数 表 ),... 基 名 n( 基 n 初 始 化 参 数 表 ), 成 员 对 象 名 1( 成 员 对 象 1 初 始 化 参 数 表 ),, 成 员 对 象 名 m( 成 员 对 象 m 初 始 化 参 数 表 ) { 其 他 初 始 化 操 作 ; 38

派 生 的 构 造 析 构 函 数 派 生 与 基 的 构 造 函 数 当 基 中 声 明 有 缺 省 构 造 函 数 或 未 声 明 构 造 函 数 时, 派 生 构 造 函 数 可 以 不 向 基 构 造 函 数 传 递 参 数, 也 可 以 不 声 明 构 造 派 生 的 对 象 时, 基 的 缺 省 构 造 函 数 将 被 调 用 当 需 要 执 行 基 中 带 形 参 的 构 造 函 数 来 初 始 化 基 数 据 时, 派 生 构 造 函 数 应 在 初 始 化 列 表 中 为 基 构 造 函 数 提 供 参 数 39

派 生 的 构 造 析 构 函 数 构 造 函 数 的 执 行 顺 序 1. 调 用 基 构 造 函 数, 调 用 顺 序 按 照 它 们 被 继 承 时 声 明 的 顺 序 ( 从 左 向 右 ) 2. 对 派 生 新 增 的 成 员 对 象 进 行 初 始 化, 初 始 化 顺 序 按 照 它 们 在 中 声 明 的 顺 序 3. 执 行 派 生 的 构 造 函 数 体 中 的 内 容 41

派 生 的 构 造 析 构 函 数 拷 贝 构 造 函 数 若 建 立 派 生 对 象 时 没 有 编 写 拷 贝 构 造 函 数, 编 译 器 会 生 成 一 个 隐 含 的 拷 贝 构 造 函 数, 该 函 数 先 调 用 基 的 拷 贝 构 造 函 数, 再 为 派 生 新 增 的 成 员 对 象 执 行 拷 贝 若 编 写 派 生 的 拷 贝 构 造 函 数, 一 般 需 要 为 基 相 应 的 拷 贝 构 造 函 数 传 递 参 数 例 如 : C::C(C &c1): B(c1) { } 42

派 生 的 构 造 析 构 函 数 例 7-4 派 生 构 造 函 数 举 例 //7_4.cpp #include <iostream> using namespace std; class Base1 { // 基 Base1, 构 造 函 数 有 参 数 public: Base1(int i) { cout << "Constructing Base1 " << i << endl; } class Base2 { // 基 Base2, 构 造 函 数 有 参 数 public: Base2(int j) { cout << "Constructing Base2 " << j << endl; } class Base3 { // 基 Base3, 构 造 函 数 无 参 数 public: Base3() { cout << "Constructing Base3 *" << endl; } 43

class Derived: public Base2, public Base1, public Base3 { // 派 生 新 Derived, 注 意 基 名 的 顺 序 public: // 派 生 的 公 有 成 员 Derived(int a, int b, int c, int d): Base1(a), member2(d), member1(c), Base2(b) { } // 注 意 基 名 的 个 数 与 顺 序,// 注 意 成 员 对 象 名 的 个 数 与 顺 序 private: Base1 member1; Base2 member2; Base3 member3; // 派 生 的 私 有 成 员 对 象 int main() { Derived obj(1, 2, 3, 4); return 0; } 运 行 结 果 : constructing Base2 2 constructing Base1 1 constructing Base3 * constructing Base1 3 constructing Base2 4 constructing Base3 * 44

派 生 的 构 造 析 构 函 数 继 承 时 的 析 构 函 数 析 构 函 数 也 不 被 继 承, 派 生 自 行 声 明 声 明 方 法 与 一 般 ( 无 继 承 关 系 时 ) 的 析 构 函 数 相 同 不 需 要 显 式 地 调 用 基 的 析 构 函 数, 系 统 会 自 动 隐 式 调 用 析 构 函 数 的 调 用 次 序 与 构 造 函 数 相 反 45

派 生 的 构 造 析 构 函 数 例 7-5 派 生 析 构 函 数 举 例 //7_5.cpp #include <iostream> using namespace std; class Base1 { // 基 Base1, 构 造 函 数 有 参 数 public: Base1(int i) { cout << "Constructing Base1 " << i << endl; } ~Base1() { cout << "Destructing Base1" << endl; } class Base2 { // 基 Base2, 构 造 函 数 有 参 数 public: Base2(int j) { cout << "Constructing Base2 " << j << endl; } ~Base2() { cout << "Destructing Base2" << endl; } class Base3 { // 基 Base3, 构 造 函 数 无 参 数 public: Base3() { cout << "Constructing Base3 *" << endl; } ~Base3() { cout << "Destructing Base3" << endl; } 46

class Derived: public Base2, public Base1, public Base3 { // 派 生 新 Derived, 注 意 基 名 的 顺 序 public: // 派 生 的 公 有 成 员 Derived(int a, int b, int c, int d): Base1(a), member2(d), member1(c), Base2(b) { } // 注 意 基 名 的 个 数 与 顺 序, 注 意 成 员 对 象 名 的 个 数 与 顺 序 private: // 派 生 的 私 有 成 员 对 象 Base1 member1; Base2 member2; Base3 member3; int main() { Derived obj(1, 2, 3, 4); return 0; } 47

例 7-5 运 行 结 果 Constructing Base2 2 Constructing Base1 1 Constructing Base3 * Constructing Base1 3 Constructing Base2 4 Constructing Base3 * Destructing Base3 Destructing Base2 Destructing Base1 Destructing Base3 Destructing Base1 Destructing Base2 48

派 生 成 员 的 标 识 与 访 问 派 生 成 员 的 访 问 派 生 成 员 的 访 问 属 性 不 可 访 问 的 成 员 私 有 成 员 保 护 成 员 公 有 成 员 两 个 问 题 唯 一 标 识 问 题 可 见 性 问 题 49

派 生 成 员 的 标 识 与 访 问 同 名 隐 藏 规 则 当 派 生 与 基 中 有 相 同 成 员 时 : 若 未 强 行 指 明, 则 通 过 派 生 对 象 使 用 的 是 派 生 中 的 同 名 成 员 如 要 通 过 派 生 对 象 访 问 基 中 被 隐 藏 的 同 名 成 员, 应 使 用 作 用 域 分 辨 符 和 基 名 来 限 定 50

派 生 成 员 的 标 识 与 访 问 例 7-6 多 继 承 同 名 隐 藏 举 例 (1) //7_6.cpp #include <iostream> using namespace std; class Base1 { // 定 义 基 Base1 public: int var; void fun() { cout << "Member of Base1" << endl; } class Base2 { // 定 义 基 Base2 public: int var; void fun() { cout << "Member of Base2" << endl; } class Derived: public Base1, public Base2 { // 定 义 派 生 Derived public: int var; // 同 名 数 据 成 员 void fun() { cout << "Member of Derived" << endl; } // 同 名 函 数 成 员 51

int main() { Derived d; Derived *p = &d; d.var = 1; // 对 象 名. 成 员 名 标 识 d.fun(); // 访 问 Derived 成 员 d.base1::var = 2; // 作 用 域 分 辨 符 标 识 d.base1::fun(); // 访 问 Base1 基 成 员 p->base2::var = 3; p->base2::fun(); // 作 用 域 分 辨 符 标 识 // 访 问 Base2 基 成 员 } return 0; 52

派 生 成 员 的 标 识 与 访 问 二 义 性 问 题 在 多 继 承 时, 基 与 派 生 之 间, 或 基 之 间 出 现 同 名 成 员 时, 将 出 现 访 问 时 的 二 义 性 ( 不 确 定 性 ) 采 用 虚 函 数 ( 参 见 第 8 章 ) 或 同 名 隐 藏 规 则 来 解 决 当 派 生 从 多 个 基 派 生, 而 这 些 基 又 从 同 一 个 基 派 生, 则 在 访 问 此 共 同 基 中 的 成 员 时, 将 产 生 二 义 性 采 用 虚 基 来 解 决 53

派 生 成 员 的 标 识 与 访 问 二 义 性 问 题 举 例 ( 一 ) class A { public: void f(); class B { public: void f(); void g() class C: public A, piblic B { public: void g(); void h(); 如 果 定 义 :C c1; 则 c1.f() 具 有 二 义 性 而 c1.g() 无 二 义 性 ( 同 名 隐 藏 ) 54

派 生 成 员 的 标 识 与 访 问 二 义 性 的 解 决 方 法 解 决 方 法 一 : 用 基 名 来 限 定 c1.a::f() 或 c1.b::f() 解 决 方 法 二 : 同 名 隐 藏 在 C 中 声 明 一 个 同 名 成 员 函 数 f(),f() 再 根 据 需 要 调 用 A::f() 或 B::f() 55

派 生 成 员 的 标 识 与 访 问 二 义 性 问 题 举 例 ( 二 ) class B { public: int b; } class B1: public B { private: int b1; class B2: public B { private: int b2; class C : public B1,public B2 { public: 有 二 义 性 : int f(); C c; private: c.b int d; c.b::b } 无 二 义 性 : c.b1::b c.b2::b 56

虚 基 虚 基 的 引 入 用 于 有 共 同 基 的 场 合 声 明 以 virtual 修 饰 说 明 基 例 :class B1:virtual public B 作 用 主 要 用 来 解 决 多 继 承 时 可 能 发 生 的 对 同 一 基 继 承 多 次 而 产 生 的 二 义 性 问 题. 为 最 远 派 生 提 供 唯 一 的 基 成 员, 而 不 重 复 产 生 多 次 拷 贝 注 意 : 在 第 一 级 继 承 时 就 要 将 共 同 基 设 计 为 虚 基 57

虚 基 虚 基 举 例 class B { public: int b; class B1: virtual public B { public: int b1; class B2: virtual public B { public: int b2; class C: public B1, public B2 { public: float d; 下 面 的 访 问 是 正 确 的 : C cobj; cobj.b; 58

虚 例 7-8 虚 基 举 例 基 + var0 : int <<virtual>> Base0 + fun0() : void Derived Base1 + var1 : int Base2 + var2 : int Base0::var0:int Base1::var1:int Base2::var2:int var :int Base0::fun0():void fun():void Derived + var : int + fun() : void 59

//7_8.cpp #include <iostream> using namespace std; class Base0 { // 定 义 基 Base0 public: int var0; void fun0() { cout << "Member of Base0" << endl; } class Base1: virtual public Base0 { // 定 义 派 生 Base1 public: // 新 增 外 部 接 口 int var1; class Base2: virtual public Base0 { // 定 义 派 生 Base2 public: // 新 增 外 部 接 口 int var2; 60

class Derived: public Base1, public Base2 { // 定 义 派 生 Derived public: // 新 增 外 部 接 口 int var; void fun() { cout << "Member of Derived" << endl; } int main() { // 程 序 主 函 数 Derived d; // 定 义 Derived 对 象 d d.var0 = 2; // 直 接 访 问 虚 基 的 数 据 成 员 d.fun0(); // 直 接 访 问 虚 基 的 函 数 成 员 return 0; } 61

虚 虚 基 及 其 派 生 构 造 函 数 基 建 立 对 象 时 所 指 定 的 称 为 最 远 派 生 虚 基 的 成 员 是 由 最 远 派 生 的 构 造 函 数 通 过 调 用 虚 基 的 构 造 函 数 进 行 初 始 化 的 在 整 个 继 承 结 构 中, 直 接 或 间 接 继 承 虚 基 的 所 有 派 生, 都 必 须 在 构 造 函 数 的 成 员 初 始 化 表 中 给 出 对 虚 基 的 构 造 函 数 的 调 用 如 果 未 列 出, 则 表 示 调 用 该 虚 基 的 默 认 构 造 函 数 在 建 立 对 象 时, 只 有 最 远 派 生 的 构 造 函 数 调 用 虚 基 的 构 造 函 数, 该 派 生 的 其 他 基 对 虚 基 构 造 函 数 的 调 用 被 忽 略 62

虚 基 有 虚 基 时 的 构 造 函 数 举 例 #include <iostream> using namespace std; class Base0 { // 定 义 基 Base0 public: Base0(int var) : var0(var) { } int var0; void fun0() { cout << "Member of Base0" << endl; } class Base1: virtual public Base0 { // 定 义 派 生 Base1 public: // 新 增 外 部 接 口 Base1(int var) : Base0(var) { } int var1; class Base2: virtual public Base0 { // 定 义 派 生 Base2 public: // 新 增 外 部 接 口 Base2(int var) : Base0(var) { } int var2; 63

class Derived: public Base1, public Base2 { // 定 义 派 生 Derived public: // 新 增 外 部 接 口 Derived(int var) : Base0(var), Base1(var), Base2(var) { } int var; void fun() { cout << "Member of Derived" << endl; } int main() { // 程 序 主 函 数 Derived d(1); // 定 义 Derived 对 象 d d.var0 = 2; // 直 接 访 问 虚 基 的 数 据 成 员 d.fun0(); // 直 接 访 问 虚 基 的 函 数 成 员 return 0; } 64

组 合 与 继 承 深 度 探 索 组 合 与 继 承 : 通 过 已 有 来 构 造 新 的 两 种 基 本 方 式 组 合 :B 中 存 在 一 个 A 型 的 内 嵌 对 象 有 一 个 (has-a) 关 系 : 表 明 每 个 B 型 对 象 有 一 个 A 型 对 象 A 型 对 象 与 B 型 对 象 是 部 分 与 整 体 关 系 B 型 的 接 口 不 会 直 接 作 为 A 型 的 接 口 65

has-a 举 例 深 度 探 索 class Engine { // 发 动 机 public: void work(); // 发 动 机 运 转 class Wheel { // 轮 子 public: void roll(); // 轮 子 转 动 class Automobile { // 汽 车 public: void move(); // 汽 车 移 动 private: Engine engine; // 汽 车 引 擎 Wheel wheels[4];//4 个 车 轮 意 义 一 辆 汽 车 有 一 个 发 动 机 一 辆 汽 车 有 四 个 轮 子 接 口 作 为 整 体 的 汽 车 不 再 具 备 发 动 机 的 运 转 功 能, 和 轮 子 的 转 动 功 能, 但 通 过 将 这 些 功 能 的 整 合, 具 有 了 自 己 的 功 能 移 动 66

公 有 继 承 的 意 义 深 度 探 索 公 有 继 承 :A 是 B 的 公 有 基 是 一 个 (is-a) 关 系 : 表 明 每 个 B 型 对 象 是 一 个 A 型 对 象 A 型 对 象 与 B 型 对 象 是 一 般 与 特 殊 关 系 回 顾 的 兼 容 性 原 则 : 在 需 要 基 对 象 的 任 何 地 方, 都 可 以 使 用 公 有 派 生 的 对 象 来 替 代 B 型 对 象 包 括 A 型 的 全 部 接 口 67

is-a 举 例 深 度 探 索 class Truck: public Automobile{ // 卡 车 public: void load( ); // 装 货 void dump( ); // 卸 货 private: class Pumper: public Automobile { // 消 防 车 public: void water(); // 喷 水 private: 意 义 卡 车 是 汽 车 消 防 车 是 汽 车 接 口 卡 车 和 消 防 车 具 有 汽 车 的 通 用 功 能 ( 移 动 ) 它 们 还 各 自 具 有 自 己 的 功 能 ( 卡 车 : 装 货 卸 货 ; 消 防 车 : 喷 水 ) 68

派 生 对 象 的 内 存 布 局 深 度 探 索 派 生 对 象 的 内 存 布 局 因 编 译 器 而 异 内 存 布 局 应 使 型 兼 容 规 则 便 于 实 现 一 个 基 指 针, 无 论 其 指 向 基 对 象, 还 是 派 生 对 象, 通 过 它 来 访 问 一 个 基 中 定 义 的 数 据 成 员, 都 可 以 用 相 同 的 步 骤 不 同 情 况 下 的 内 存 布 局 单 继 承 : 基 数 据 在 前, 派 生 新 增 数 据 在 后 多 继 承 : 各 基 数 据 按 顺 序 在 前, 派 生 新 增 数 据 在 后 虚 继 承 : 需 要 增 加 指 针, 间 接 访 问 虚 基 数 据 69

单 继 承 情 形 深 度 探 索 class Base { class Derived: public Base { Derived *pd = new Derived(); Base *pb = pd; pb, pd Base 数 据 成 员 Derived 新 增 数 据 成 员 Derived 对 象 Derived 型 指 针 pd 转 换 为 Base 型 指 针 时, 地 址 不 需 要 改 变 70

多 继 承 情 形 深 度 探 索 class Base1 { class Base2 { class Derived: public Base1, public Base2 { Derived *pd = new Derived(); Base1 *pb1 = pd; Base2 *pb2 = pd; pb1, pd pb2 Base1 数 据 成 员 Base2 数 据 成 员 Derived 新 增 数 据 成 员 Derived 对 象 Derived 型 指 针 pd 转 换 为 Base2 型 指 针 时, 原 地 址 需 要 增 加 一 个 偏 移 量 71

虚 拟 继 承 情 形 深 度 探 索 class Base0 { class Base1: virtual public Base0 { class Base2: virtual public Base0 { class Derived: public Base1, public Base2 { Derived *pd = new Derived(); Base1 *pb1 = pd; Base2 *pb2 = pd; Base0 *pb0 = pb1; pb1, pd pb2 pb0 Base0 指 针 Base1 新 增 数 据 成 员 Base0 指 针 Base2 新 增 数 据 成 员 Base0 数 据 成 员 Derived 对 象 通 过 指 针 间 接 访 问 虚 基 的 数 据 成 员 72

基 向 派 生 的 转 换 深 度 探 索 基 向 派 生 的 转 换 基 指 针 可 以 转 换 为 派 生 指 针 基 引 用 可 以 转 换 为 派 生 引 用 需 要 用 static_cast 显 式 转 换 例 : Base *pb = new Derived(); Derived *pd = static_cast<derived *>(pb); Derived d; Base &rb = d; Derived &rd = static_cast<derived &>(rb); 73

型 转 换 时 的 注 意 事 项 (1) 深 度 探 索 基 对 象 一 般 无 法 被 显 式 转 换 为 派 生 对 象 对 象 到 对 象 的 转 换, 需 要 调 用 构 造 函 数 创 建 新 的 对 象 若 派 生 有 构 造 函 数 接 收 基 对 象 ( 或 基 引 用 ) 的 参 数, 才 可 行 Base b; Derived d = static_cast<derived>(b); 执 行 基 向 派 生 的 转 换 时, 一 定 要 确 保 被 转 换 的 指 针 和 引 用 所 指 向 或 引 用 的 对 象 符 合 转 换 的 目 的 型 : 对 于 Derived *pd = static_cast<derived *>(pb); 一 定 要 保 证 pb 所 指 向 的 对 象 具 有 Derived 型, 或 者 是 Derived 型 的 派 生 74

型 转 换 时 的 注 意 事 项 (2) 深 度 探 索 如 果 A 型 是 B 型 的 虚 基,A 型 指 针 无 法 通 过 static_cast 显 式 转 换 为 B 型 的 指 针 可 以 结 合 虚 继 承 情 况 下 的 对 象 内 存 布 局, 思 考 为 什 么 不 允 许 这 种 转 换 void 指 针 参 加 的 转 换, 可 能 导 致 不 可 预 期 的 后 果 : 例 :Derived 公 共 继 承 自 Base1 和 Base2 Derived *pd = new Derived(); void *pv = pd; // 将 Derived 指 针 转 换 为 void 指 针 Base2 *pb = static_cast<base2 *>(pv); 转 换 后 pb 与 pd 有 相 同 的 地 址, 而 正 常 的 转 换 下 应 有 一 个 偏 移 量 结 论 : 有 void 指 针 参 与 的 转 换, 兼 容 性 规 则 不 适 用 更 安 全 更 灵 活 的 基 向 派 生 转 换 方 式 dynamic_cast, 将 在 下 一 章 介 绍 75

小 结 与 复 习 建 议 主 要 内 容 的 继 承 成 员 的 访 问 控 制 单 继 承 与 多 继 承 派 生 的 构 造 和 析 构 函 数 成 员 的 标 识 与 访 问 达 到 的 目 标 理 解 的 继 承 关 系, 学 会 使 用 继 承 关 系 实 现 代 码 的 重 用 76