资源描述
面向对象程序设计西 南 交 通 大 学 信 息 科 学 与 技 术 学 院主 讲 教 师 :喻 琇 瑛 第 五 章 C+程 序 的 结 构u 标 识 符 的 作 用 域 、 可 见 性 、 生 存 期u 类 成 员 的 共 享 与 保 护 5.1 标识符的作用域与可见性 作 用 域 : 讨 论 的 是 标 识 符 的 有 效 范 围 ;可 见 性 : 讨 论 的 是 标 识 符 是 否 可 以 引 用 的 问 题 。二 者 既 相 互 联 系 , 但 又 存 在 着 差 异 。1.作 用 域定 义 : 是 一 个 标 识 符 在 程 序 正 文 中 有 效 的 区 域 。标 识 符 的 引 入 与 声 明 有 关 , 作 用 域 开 始 于 标 识 符 的 声明 处 。在 C+中 , 作 用 域 包 括 : 函 数 原 型 作 用 域 、 块 作 用 域( 局 部 作 用 域 ) 、 类 作 用 域 和 文 件 作 用 域 这 几 种 。 1 ) 函 数 原 型 作 用 域在 C+中 , 最 小 的 作 用 域 是 函 数 原 型 作 用 域 。 在 函 数 原型 声 明 时 形 式 参 数 的 作 用 范 围 就 是 函 数 原 型 作 用 域 。例 如 : int GetScore( int score) ;这 里 , 标 识 符 score的 作 用 范 围 ( 即 作 用 域 ) 就 是 在 函数 GetScore的 左 右 括 号 之 间 , 在 程 序 的 其 他 地 方 无 法引 用 这 个 标 识 符 , 这 里 , 我 们 将 标 识 符 score的 作 用 域就 称 为 函 数 原 型 作 用 域 。说 明 : 对 于 这 种 情 况 , 形 参 可 以 省 略 , 声 明 中 加 上 形参 的 目 的 是 提 高 程 序 的 可 读 性 。5.1 标识符的作用域与可见性(续1) 2 ) 块 作 用 域块 : 块 是 一 对 大 括 号括 起 来 的 程 序 。块 作 用 域 : 当 标 识 符的 声 明 出 现 在 一 对 花括 号 所 括 起 来 的 一 段程 序 ( 块 : 复 合 语 句 )内 时 , 该 标 识 符 的 作用 域 从 声 明 点 开 始 ,到 块 结 束 处 为 止 , 该作 用 域 的 范 围 具 有 局部 性 。 void fn ( int y ) y的 作 用 域 从 此 开 始int x=1; x的 作 用 域 从 此 开 始if (xy)cout x endl;elsecout y A这 样 的 表 达 式 中 , 常 用 指 向 C类 对 象 的 指 针 来访 问 类 的 对 象 的 成 员 , 这 里 也 具 有 类 作 用 域 。 5.1 标识符的作用域与可见性(续3) 4) 文 件 作 用 域文 件 作 用 域 : 在 所 有 函 数 定 义 之 外 说 明 的 , 不 属 于前 面 各 个 作 用 域 中 出 现 的 声 明 , 具 有 文 件 作 用 域 。其 作 用 域 开 始 于 声 明 点 , 结 束 于 文 件 尾 。5.1 标识符的作用域与可见性(续4) 例 : #include int a; /a被 声 明 为 一 个 全 局 变 量 , 具 有 文 件 作 用 域void main( ) a=5; /为 具 有 文 件 作 用 域 的 a赋 初 值 /大 括 号 中 为 一 个 子 块 int a; /在 子 块 中 定 义 了 局 部 变 量 a, 具 有 块 作 用 域 a=3; /为 具 有 块 作 用 域 的 a赋 初 值 cout“a=”aendl; /子 块 结 束 cout“a=”aendl; /块 结 束 , 所 以 只 有 具 有 文 件作 用 域 的 a有 效 , 输 出 5 5.1 标识符的作用域与可见性(续5) 2. 可 见 性 文 件 作 用 域类 作 用 域块 作 用 域 可 见 性 是 从 标 识 符 引 用 时 是 否 可 见 的 角 度 看 。 程 序运 行 到 某 一 点 , 能 够 引 用 到 的 标 识 符 , 就 是 该 处 可 见 的标 识 符 。 作 用 域 由 大 到 小 见 下 图 :5.1 标识符的作用域与可见性(续6) 可 见 性 的 一 般 规 则 是 : 标 识 符 要 先 声 明 , 后 引 用 。 在 同 一 作 用 域 中 , 不 能 声 明 同 名 的 标 识 符 。 对 于 在 不 同 的 作 用 域 声 明 的 标 识 符 , 遵 循 的 原 则 是 : 当 在 没 有 互 相 包 含 关 系 的 不 同 作 用 域 中 声 明 的 同 名 的 标识 符 互 相 不 影 响 ; 当 存 在 具 有 包 含 关 系 的 两 个 或 多 个 作 用 域 时 , 在 外 层 声明 了 标 识 符 后 : 如 果 内 层 中 没 有 声 明 与 之 同 名 的 标 识 符, 则 外 层 标 识 符 在 内 层 可 见 。 如 果 内 层 中 声 明 了 与 外 层同 名 的 标 识 符 , 则 外 层 标 识 符 在 内 层 不 可 见 。 ( 例 如 :前 面 的 例 5-1) 如 果 被 隐 藏 的 是 全 局 变 量 , 则 可 用 符 号 “ : : ” 来 引 用该 全 局 变 量 。5.1 标识符的作用域与可见性(续7完) 5 . 2 生存期 生 存 期 : 变 量 和 对 象 从 产 生 到 结 束 的 这 段 时 间 就称 为 生 存 期 。 在 生 存 期 内 , 对 象 保 持 其 状 态 , 变量 保 持 其 值 。 1) 静 态 生 存 期 : 变 量 在 固 定 的 数 据 区 中 分 配 空 间的 , 具 有 静 态 生 命 期 。 或 者 说 : 如 果 对 象 的 生 存期 与 程 序 的 运 行 期 相 同 , 称 其 具 有 静 态 生 存 期 。 通 常 有 两 种 情 况 下 , 对 象 具 有 静 态 生 存 期 : 在 文 件 作 用 域 中 声 明 的 对 象 在 函 数 内 部 的 块 作 用 域 中 用 static关 键 字 声 明 的对 象 。 例 如 : static int score; 说 明 : 静 态 生 命 期 的 变 量 , 若 无 显 式 初 始 化 , 则 自 动初 始 化 为 0。 函 数 驻 在 代 码 区 , 也 具 有 静 态 生 存 期 。 在 函 数内 部 可 以 声 明 静 态 生 存 期 的 变 量 , 即 静 态 局 部变 量 ( 加 static) 。 5 . 2 生存期(续1) 2) 局 部 生 存 期 : 在 函 数 内 部 声 明 的 变 量 或 者 是 块中 声 明 的 变 量 具 有 局 部 生 存 期 。 这 种 变 量 的 生存 期 开 始 于 程 序 执 行 经 过 其 声 明 点 时 , 而 结 束于 其 作 用 域 结 束 处 。说 明 : 具 有 局 部 生 存 期 的 变 量 驻 在 内 存 的 栈 区 。 具 有 局 部 生 存 期 的 变 量 如 果 未 被 初 始 化 , 则 内容 不 可 知 。5 . 2 生存期(续2) #include int i=1; /i为 全 局 变 量 , 具 有 文 件 作 用 域 , 静 态 生 存 期void main(void) static int a; /a为 静 态 局 部 变 量 , 具 有 全 局 寿 命 , 局 部 可 见 int b=-10; int c=0; void other(void); cout-MAIN-n; couti:ia:ab:bc:cendl; /第 一 次 c=c+8; other(); /调 用 other cout-MAIN-n; couti:ia: ab: bc: cendl; i=i+10; other(); /调 用 other 5 . 2 生存期(续3) void other(void) static int a=2; static int b; int c=10; /c为 局 部 变 量 , 每 次 进 入 函 数 时 都 被 初 始 化 a=a+2; i=i+32; c=c+5; cout-OTHER-n; couti: ia: ab: bc:cendl; b=a; a, b为 静 态 局 部 变 量 , 具 有全 局 寿 命 , 静 态 生 存 期 , 局部 可 见 , 只 在 第 一 次 进 入 函数 时 被 初 始 化5 . 2 生存期(续4) 3) 动 态 生 命 期 : 这 种 生 命 期 由 程 序 中 特 定 的 函 数 调 用 (malloc( )和 free( ) 或 操 作 符 (new和 delete)来 创 建 和 释 放 。 具 有 这 种 生 命 期 的 变 量 驻 在 内 存 的 堆 中 。 当 用 函 数malloc( ) 或 new为 变 量 分 配 空 间 时 , 生 命 期 开 始 ,当 用 free( ) 或 delete释 放 该 变 量 的 空 间 或 程 序 结 束 时, 生 命 期 结 束 。5 . 2 生存期(续5完) 5 . 3 数据与函数 数 据 和 函 数 的 关 系 包 括 : 函 数 读 数 据 的 访 问 权 限、 函 数 之 间 的 数 据 共 享 以 及 对 共 享 数 据 的 保 护 。 在 C+中 , 一 般 可 以 通 过 局 部 变 量 、 全 局 变 量 、 类的 数 据 成 员 、 类 的 静 态 成 员 以 及 友 元 来 实 现 函 数 之 间的 数 据 共 享 。 1、 局 部 变 量 通 常 , 定 义 于 函 数 内 部 的 变 量 称 为 局 部 变 量 , 一般 来 说 就 是 具 有 块 作 用 域 的 变 量 。 块 作 用 域 的 范 围 是从 变 量 定 义 处 开 始 , 到 块 的 结 束 处 为 止 。 作 用 : 由 于 变 量 具 有 局 部 作 用 域 , 因 此 在 不 同 函数 体 内 的 局 部 变 量 是 互 相 不 可 见 的 , 这 就 很 好 的 实 现了 函 数 之 间 的 数 据 隐 蔽 。 2、 全 局 变 量通 常 , 定 义 于 函 数 外 部 的 变 量 称 为 全 局 变 量 。 作 用 : 将 数 据 存 放 在 全 局 变 量 中 , 不 同 的 函 数 在 不 同的 地 方 可 以 对 同 一 个 全 局 变 量 进 行 访 问 , 实 现 了 这 些函 数 之 间 的 数 据 共 享 。 5 . 3 数据与函数(续1) 3、 数 据 成 员 在 结 构 化 程 序 设 计 中 , 只 有 参 数 传 递 和 全 局 变 量这 两 种 方 式 来 实 现 数 据 共 享 , 而 在 C+中 , 还 可 以 通过 数 据 成 员 实 现 数 据 的 隐 藏 和 共 享 。 类 的 成 员 包 括 了 函 数 成 员 和 数 据 成 员 。 类 的 数 据成 员 可 以 被 同 类 中 的 任 何 函 数 访 问 , 从 而 在 类 的 内 部函 数 之 间 实 现 了 数 据 的 共 享 。 作 用 : 实 现 了 共 享 和 隐 藏 的 两 全 。 一 方 面 在 类 内 部 函数 之 间 实 现 了 数 据 的 共 享 , 另 一 方 面 可 以 适 当 设 置 访问 控 制 属 性 , 限 制 这 种 共 享 , 将 共 享 限 制 在 类 的 范 围之 内 。5 . 3 数据与函数(续2完) 5 . 4 静态成员class studentprivate:int studentNo:char *name;.问 题 : 如 何 统 计 学 生 总 数 ? 如 果 用 类 外 的 变 量 存 储 总 数 , 不 能 实 现 数 据 的 隐 藏 ; 如 果 在 类 中 增 加 一 个 数 据 成 员 来 存 放 总 数 , 那 么 每 个对 象 都 会 存 储 一 个 副 本 , 就 会 产 生 冗 余 , 而 且 每 个 对分 别 维 护 一 个 “ 总 数 ” , 将 造 成 数 据 的 不 一 致 性 。 静 态 成 员 的 内 存区对 象 1对 象 2对 象 3 对 象 4对 象 5对 象 6分 两 种 :静 态 数 据 成 员静 态 函 数 成 员5 . 4 静态成员(续1) 1、 静 态 数 据 成 员对 比 : 类 的 普 通 数 据 成 员 : 在 每 个 对 象 中 都 拥 有 一 个 拷 贝 ,即 每 个 对 象 的 同 名 数 据 成 员 可 以 分 别 存 储 不 同 数 值 ; 类 的 静 态 数 据 成 员 : 以 static关 键 字 来 声 明 , 每 个 类只 有 一 个 拷 贝 , 这 个 类 的 所 有 对 象 共 同 维 护 使 用 这 个拷 贝 , 从 而 实 现 同 一 类 的 不 同 对 象 之 间 的 数 据 共 享 。静 态 数 据 成 员 的 声 明 : 在 类 的 声 明 中 对 静 态 数 据 成 员 进 行 引 用 性 说 明 , 必 须 在 文 件 作 用 域 的 某 个 地 方 使 用 类 名 限 定 进 行 定 义性 说 明 , 同 时 可 以 进 行 初 始 化 。注 意 : 静 态 数 据 成 员 在 声 明 时 如 果 没 有 赋 初 值 , 系 统 会 自动 为 其 赋 初 值 为 0。5 . 4 静态成员(续2) 例 : #include class point public:point( int xx=0,int yy=0) x=xx; y=yy; countP+; point( point &p) ;int getX( ) return x; void getC( ) coutobject id: countPendl; private:int x,y;static int countP; 5 . 4 静态成员(续3) point: : point( point & p) /拷 贝 构 造 x=p.x;y=p.y;countP+;int point: : countP=0; void main( ) point A( 4,5) ;coutA: endl;A.getC( ) ; Point B( A) ; coutB: endl;B.getC( ) ; 运 行 结 果 : A:Object id: 1BObject id: 2 对 静 态 数 据 成 员 的 定 义 性说 明 和 初 始 化 , 不 能 缺 少 5 . 4 静态成员(续4) 2、 静 态 函 数 成 员优 点 : 不 依 赖 于 任 何 对 象 , 可 以 直 接 访 问 静 态 数 据 。1) 访 问 静 态 数 据5 . 4 静态成员(续5) #include classs Pointpublic:Point( int xx=0, int yy=0) X=xx; Y=yy; countP+; Point( Point &p) ;int getX( ) return X; int getY( ) return Y; static void getC( ) cout“object id is ”countPendl; /静 态 函 数 成 员 , 将 原 例 中 的 getC( ) 改 为 了 staticprivate: int X, Y; static int countP; /静 态 数 据 成 员 引 用 性 说 明;5 . 4 静态成员(续6) Point: : Point( Point &p) X=p.X;Y=p.Y;CountP+;int Point: : countP=0;void main( )Point A( 4, 5) ;Cout“Point A, ” A.getX( ) “, ” A.getY( ) ;A.getC( ) ; Point B( A) ;Cout“Point B, ” B.getX( ) “, ” B.getY( ) ;Point: : getC( ) ;/利 用 类 名 引 用 , 输 出 对 象 号 , 不 需 要 用 对 象 名 来 引 用5 . 4 静态成员(续7) 2) 访 问 非 静 态 数 据 成 员 静 态 成 员 函 数 可 以 直 接 访 问 该 类 的 静 态 数 据和 函 数 成 员 ; 如 果 要 访 问 非 静 态 数 据 成 员 , 则 必须 通 过 参 数 传 递 方 式 得 到 对 象 名 , 然 后 通 过 对 象名 来 访 问 。 5 . 4 静态成员(续8) 例 : class pointpublic:static void f( point a) ;private:int x, y;void point: : f( point a)coutx; /错 误 , 不 能 直 接 对 x进 行 引 用couta.x; /正 确5 . 4 静态成员(续9完) 5 . 5 友元1.友元函数友 元 函 数 : 是 在 类 声 明 中 由 关 键 字 friend修 饰 的 非 成员 函 数 。 友 元 函 数 的 特 点 : 是 能 够 访 问 类 中 的 私 有 成 员 的 非 成员 函 数 。 友 元 函 数 从 语 法 上 看 , 它 与 普 通 函 数 一 样 ,即 在 定 义 上 和 调 用 上 与 普 通 函 数 一 样 。 下 面 举 一 例 子说 明 友 元 函 数 的 应 用 。 注 意 : 友 元 函 数 可 以 是 一 个 普 通 函 数 或 其 他 类 的 成 员函 数 , 它 不 是 本 类 的 成 员 函 数 , 但 在 友 元 函 数 体 中 可以 通 过 对 象 名 访 问 类 的 私 有 和 保 护 成 员 。 例 1:class Pointpublic: Point( double xx, double yy) x=xx; y=yy; double Getx( ) ; friend double Distance( Point &a, Point &b) ; /声 明 友 元 函 数 private: double x, y;double Point: : Getx( ) return x; double Distance( Point &a, Point &b) double dx =a.x-b.x; double dy=a.y-b.y; return sqrt( dx*dx+dy*dy) ; 直 接 访 问私 有 数 据 5 . 5 友元(续1) void main( ) Point p1( 3.0, 4.0) , p2( 6.0, 8.0) ;p1.Getxy( ) ;p2.Getxy( ) ;double d=Distance( p1, p2) ; coutDistance isdendl; 注 意 , Distance是 一个 外 部 函 数 , 而 不 是类 point的 公 有 函 数 ,所 以 这 里 直 接 调 用5 . 5 友元(续2) 2. 友元类 友 元 除 了 前 面 讲 过 的 函 数 以 外 , 友 元 还 可 以 是 类 ,即 一 个 类 可 以 作 另 一 个 类 的 友 元 。 当 一 个 类 作 为 另 一个 类 的 友 元 时 , 这 就 意 味 着 这 个 类 的 所 有 成 员 函 数 都是 另 一 个 类 的 友 元 函 数 。 语 法 形 式 : class B . friend class A; /声 明 A类 为 B类 的 友 元 类 . ;5 . 5 友元(续3) 例 # include class A friend class B; /声 明 B为 A类 的 友 元 public: void display( ) coutxendl; int getx( ) return x; private: int x;5 . 5 友元(续4) class B public:void set( int i) ;void display( ) ; private:A a;void B: : set( int i) a.x=i;couta.xendl; 由 于 B是 A的 友 元 , 所 以其 成 员 函 数 中 可 以 访 问 A类 对 象 的 私 有 成 员 ;5 . 5 友元(续5) 注 意 友 元 关 系 是 单 向 的 , 不 继 承 , 不 传 递5 . 5 友元(续6) 5.6 共享数据的保护 问 题 : 在 C+中 , 我 们 以 数 据 隐 藏 来 保 证 数 据 的 安 全 性 ,但 同 时 又 采 取 各 种 方 式 进 行 数 据 共 享 , 破 坏 了 数 据 的 安全 性 。解 决 : 对 于 既 需 要 共 享 、 又 需 要 防 止 改 变 的 数 据 应 该 声明 为 常 量 进 行 保 护 , 因 为 常 量 在 程 序 运 行 期 间 是 不 可 改变 的 。下 面 分 别 介 绍 常 引 用 、 常 对 象 和 对 象 的 常 成 员 。 5.6 共享数据的保护(续1) 1.常 引 用使 用 const修 饰 符 可 以 说 明 为 常 引 用 , 常 引 用 所 引 用 的 对 象不 能 被 更 新 。 其 定 义 格 式 如 下 : const & 例 如 : const double & v; 例 P140 例 5-7 在 实 际 应 用 中 , 常 指 针 和 常 引 用 往 往 用 来 做 函 数 的 形 参 , 这样 的 参 数 称 为 常 参 数 。 2. 常 对 象常 对 象 是 指 对 象 常 量 , 定 义 格 式 如 下 : const 或 者const 例 : class clock . clock const myclock( 0, 0, 0) ;定 义 常 对 象 时 , 同 样 要 进 行 初 始 化 , 并 且 该 对 象 不 能 再被 更 新 , 修 饰 符 const可 放 在 类 名 后 面 , 也 可 放 在 前 面 。注 意 : 常 对 象 必 须 进 行 初 始 化 常 对 象 不 能 被 更 新 常 对 象5.6 共享数据的保护(续2) 3. 用 const修 饰 的 类 成 员1) 常 成 员 函 数使 用 const关 键 字 进 行 说 明 的 成 员 函 数 , 称 为 常 成 员 函数 。 只 有 常 成 员 函 数 才 有 资 格 操 作 常 量 或 常 对 象 , 没有 使 用 const关 键 字 说 明 的 成 员 函 数 不 能 用 来 操 作 常 对象 。 所 以 , 所 有 的 门 对 常 对 象 都 是 关 闭 的 , 只 有 常 成员 函 数 是 为 常 对 象 所 提 供 的 门 ( 接 口 ) 。常 成 员 函 数 语 法 形 式 : ( ) const;其 中 , const是 加 在 函 数 说 明 后 面 的 类 型 修 饰 符 , 它 是函 数 类 型 的 一 个 组 成 部 分 , 因 此 , 在 函 数 实 现 部 分 也要 带 const关 键 字 。 下 面 举 一 例 子 说 明 常 成 员 函 数 的 特征 。5.6 共享数据的保护(续3) 5.6 共享数据的保护(续4) 2) 常 数 据 成 员 类 型 修 饰 符 const不 仅 可 以 说 明 成 员 函 数 , 也 可 以 说明 数 据 成 员 。 由 于 const类 型 对 象 必 须 被 初 始 化 , 并 且 不 能 更 新 ,因 此 , 在 类 中 说 明 了 const数 据 成 员 时 , 只 能 通 过 成 员 初始 化 列 表 的 方 式 来 生 成 构 造 函 数 对 数 据 成 员 初 始 化 。 5.6 共享数据的保护(续5) class Apublic:A( int i) ;void print( ) ;const int & r;private:const int a;static const int b; ;const int A: : b=10;A:A( int i) : a( i) , r( a) void A: : print( )couta“:b“:rendl;void main( ) A a1( 100) , a2( 0) ; a1.print( ) ; a2.print( ) ; 运 行 结 果 为 :100: 10: 1000: 10: 0 作 业 理 解 实 例 5-11并 上 机 调 试 5.11, 5.12 , 5.14
展开阅读全文