1、1C+课 程 讲 义1 、 C+对 C 的 扩 展1 简 单 的 C+程 序1 .1 求 圆 的 周 长 和 面 积数 据 描 述 :半 径 , 周 长 , 面 积 均 用 实 型 数 表 示数 据 处 理 :输 入 半 径 r;计 算 周 长 = 2 *r ;计 算 面 积 = * r2 ;输 出 半 径 , 周 长 , 面 积 ;方 法 1 : 用 结 构 化 方 法 编 程 , 求 圆 的 周 长 和 面 积/ count the girth and area of circle#includeusing name std;void main () double r, girth, ar
2、ea ;const double PI = 3 .1 4 1 5 ;cout r ; /输 入girth = 2 * PI * r ;area = PI * r * r ;cout using name std;class Circle double radius ; /成 员 变 量public : /类 的 访 问 控 制void Set_Radius( double r ) radius = r ; /成 员 函 数double Get_Radius() return radius ; /通 过 成 员 函 数 设 置 成 员 变 量double Get_Girth() return 2
3、 * 3 .1 4 f * radius ; /通 过 成 员 函 数 获 取 成 员 变 量double Get_Area() return 3 .1 4 f * radius * radius ; ;void main() Circle A, B ; /用 类 定 义 对 象A.Set_Radius( 6 .2 3 ) ; /类 的 调 用cout using namespace std;/c+的 命 名 空 间class circlepublic:double r;double pi = 3 .1 4 1 5 9 2 6 ;double area = pi*r*r;int main()
4、circle pi;cout pi.r;cout 和 格 式 不 一 样 , 前 者 没 有 后 缀 , 实 际 上 , 在 你 的 编 译 器 include文 件 夹 里 面 可 以 看 到 , 二 者 是 两 个 文 件 , 打 开 文 件 就 会 发 现 , 里 面 的 代 码 是 不 一 样 的 。 后 缀为 .h的 头 文 件 c+标 准 已 经 明 确 提 出 不 支 持 了 , 早 些 的 实 现 将 标 准 库 功 能 定 义 在 全 局 空 间 里 ,声 明 在 带 .h 后 缀 的 头 文 件 里 , c+标 准 为 了 和 C 区 别 开 , 也 为 了 正 确 使 用
5、 命 名 空 间 , 规 定 头文 件 不 使 用 后 缀 .h。 因 此 ,1 ) 当 使 用 时 , 相 当 于 在 c 中 调 用 库 函 数 , 使 用 的 是 全 局 命 名 空 间 , 也 就 是早 期 的 c+实 现 ;2 ) 当 使 用 的 时 候 , 该 头 文 件 没 有 定 义 全 局 命 名 空 间 , 必 须 使 用 namespace std;这 样 才 能 正 确 使 用 cout。二 : 由 于 namespace 的 概 念 , 使 用 C+标 准 程 序 库 的 任 何 标 识 符 时 , 可 以 有 三 种 选 择 :1 、 直 接 指 定 标 识 符 。
6、 例 如 std:ostream 而 不 是 ostream。 完 整 语 句 如 下 : std:cout 和 等 等 这 样 的 头 文 件 , 一 个 是 为 了 兼 容 以 前 的 C+代 码 ,一 个 是 为 了 支 持 新 的 标 准 。 命 名 空 间 std 封 装 的 是 标 准 程 序 库 的 名 称 , 标 准 程 序 库 为 了 和 以前 的 头 文 件 区 别 , 一 般 不 加 “.h“2 C+命 名 空 间 定 义 及 使 用 语 法/*在 C+中 , 名 称 ( name) 可 以 是 符 号 常 量 、 变 量 、 宏 、 函 数 、 结 构 、 枚 举 、
7、类 和 对 象 等 等 。为 了 避 免 , 在 大 规 模 程 序 的 设 计 中 , 以 及 在 程 序 员 使 用 各 种 各 样 的 C+库 时 , 这 些 标 识 符 的命 名 发 生 冲 突 ,标 准 C+引 入 了 关 键 字 namespace( 命 名 空 间 /名 字 空 间 /名 称 空 间 /名 域 ) , 可 以 更 好 地控 制 标 识 符 的 作 用 域 。*/*std 是 c+标 准 命 名 空 间 , c+标 准 程 序 库 中 的 所 有 标 识 符 都 被 定 义 在 std 中 , 比 如 标 准 库 中的 类 iostream、 vector等 都 定
8、 义 在 该 命 名 空 间 中 , 使 用 时 要 加 上 using 声 明 (using namespace std) 或 using 指 示 (如std:string、std:vector).*/*C 中 的 命 名 空 间在 C 语 言 中 只 有 一 个 全 局 作 用 域C 语 言 中 所 有 的 全 局 标 识 符 共 享 同 一 个 作 用 域标 识 符 之 间 可 能 发 生 冲 突C+中 提 出 了 命 名 空 间 的 概 念命 名 空 间 将 全 局 作 用 域 分 成 不 同 的 部 分不 同 命 名 空 间 中 的 标 识 符 可 以 同 名 而 不 会 发 生 冲
9、 突命 名 空 间 可 以 相 互 嵌 套全 局 作 用 域 也 叫 默 认 命 名 空 间*/*C+命 名 空 间 的 定 义 :namespace name */*C+命 名 空 间 的 使 用 :使 用 整 个 命 名 空 间 : using namespace name;使 用 命 名 空 间 中 的 变 量 : using name:variable;9使 用 默 认 命 名 空 间 中 的 变 量 : :variable默 认 情 况 下 可 以 直 接 使 用 默 认 命 名 空 间 中 的 所 有 标 识 符*/3 C+命 名 空 间 编 程 实 践namespace Name
10、SpaceA int a = 0;namespace NameSpaceB int a = 1;namespace NameSpaceC struct Teacher char name10;int age;int main() using namespace NameSpaceA;using NameSpaceB:NameSpaceC:Teacher;printf(“a = %dn“, a);printf(“a = %dn“, NameSpaceB:a);NameSpaceB:NameSpaceC:Teacher t2Teacher t1 = “aaa“, 3;printf(“t1.name
11、 = %sn“, t1.name);printf(“t1.age = %dn“, t1.age);system(“pause“);return 0;1 04 结 论1) 当 使 用 的 时 候 , 该 头 文 件 没 有 定 义 全 局 命 名 空 间 , 必 须 使 用 namespacestd;这 样 才 能 正 确 使 用 cout。 若 不 引 入 using namespace std ,需 要 这 样 做 。 std:cout。2 ) c+标 准 为 了 和 C 区 别 开 , 也 为 了 正 确 使 用 命 名 空 间 , 规 定 头 文 件 不 使 用 后 缀 .h。3 ) C
12、+命 名 空 间 的 定 义 : namespace name 4 ) using namespace NameSpaceA;5 ) namespce 定 义 可 嵌 套 。4 .2 “ 实 用 性 ” 增 加#include “iostream“using namespace std;/C 语 言 中 的 变 量 都 必 须 在 作 用 域 开 始 的 位 置 定 义 ! !/C+中 更 强 调 语 言 的 “ 实 用 性 ” , 所 有 的 变 量 都 可 以 在 需 要 使 用 时 再 定 义 。int main1 1 () int i = 0 ;printf(“ddd“);int k;
13、system(“pause“);return 0 ;4 .3 register 关 键 字 增 强/register 关 键 字 请 求 编 译 器 让 变 量 a 直 接 放 在 寄 存 器 里 面 , 速 度 快/在 c 语 言 中 register 修 饰 的 变 量 不 能 取 地 址 , 但 是 在 c+里 面 做 了 内 容/*/1register 关 键 字 的 变 化register 关 键 字 请 求 “ 编 译 器 ” 将 局 部 变 量 存 储 于 寄 存 器 中C 语 言 中 无 法 取 得 register 变 量 地 址在 C+中 依 然 支 持 register
14、关 键 字C+编 译 器 有 自 己 的 优 化 方 式 , 不 使 用 register 也 可 能 做 优 化C+中 可 以 取 得 register 变 量 的 地 址1 1/2C+编 译 器 发 现 程 序 中 需 要 取 register 变 量 的 地 址 时 , register 对 变 量 的 声 明 变 得 无 效 。/3早 期 C 语 言 编 译 器 不 会 对 代 码 进 行 优 化 , 因 此 register 变 量 是 一 个 很 好 的 补 充 。*/int main2 2 () register int a = 0 ;printf(“system(“pause“
15、);return 0 ;其 他 补 充 : 请 阅 读 register 关 键 字 常 识 课 外 阅 读 .docx4 .4 变 量 检 测 增 强/*在 C 语 言 中 , 重 复 定 义 多 个 同 名 的 全 局 变 量 是 合 法 的在 C+中 , 不 允 许 定 义 多 个 同 名 的 全 局 变 量C 语 言 中 多 个 同 名 的 全 局 变 量 最 终 会 被 链 接 到 全 局 数 据 区 的 同 一 个 地 址 空 间 上int g_var;int g_var = 1 ;C+直 接 拒 绝 这 种 二 义 性 的 做 法 。*/int main(int argc, ch
16、ar *argv) printf(“g_var = %dn“, g_var);return 0 ;4 .5 struct 类 型 加 强struct 类 型 的 加 强 :C 语 言 的 struct 定 义 了 一 组 变 量 的 集 合 , C 编 译 器 并 不 认 为 这 是 一 种 新 的 类 型C+中 的 struct 是 一 个 新 类 型 的 定 义 声 明struct Student1 2 char name1 0 0 ;int age;int main(int argc, char *argv) Student s1 = “wang“, 1 ;Student s2 = “w
17、ang2 “, 2 ;return 0 ;4 .6 C+中 所 有 的 变 量 和 函 数 都 必 须 有 类 型/*C+中 所 有 的 变 量 和 函 数 都 必 须 有 类 型C 语 言 中 的 默 认 类 型 在 C+中 是 不 合 法 的函 数 f 的 返 回 值 是 什 么 类 型 , 参 数 又 是 什 么 类 型 ?函 数 g 可 以 接 受 多 少 个 参 数 ?*/更 换 成 .cpp 试 试f(i)printf(“i = %dn“, i);g() return 5 ;int main(int argc, char *argv) f(1 0 );printf(“g() = %
18、dn“, g(1 , 2 , 3 , 4 , 5 );1 3getchar();return 0 ;总 结 :/*在 C 语 言 中int f( ); 表 示 返 回 值 为 int, 接 受 任 意 参 数 的 函 数int f(void); 表 示 返 回 值 为 int 的 无 参 函 数在 C+中int f( );和 int f(void)具 有 相 同 的 意 义 , 都 表 示 返 回 值 为 int 的 无 参 函 数*/C+更 加 强 调 类 型 , 任 意 的 程 序 元 素 都 必 须 显 示 指 明 类 型4 .2 -4 .6 属 于 语 法 级 别 的 增 强 。4 .
19、7 新 增 Bool 类 型 关 键 字/*C+中 的 布 尔 类 型C+在 C 语 言 的 基 本 类 型 系 统 之 上 增 加 了 boolC+中 的 bool 可 取 的 值 只 有 true 和 false理 论 上 bool 只 占 用 一 个 字 节 ,如 果 多 个 bool 变 量 定 义 在 一 起 , 可 能 会 各 占 一 个 bit, 这 取 决 于 编 译 器 的 实 现true 代 表 真 值 , 编 译 器 内 部 用 1 来 表 示false 代 表 非 真 值 , 编 译 器 内 部 用 0 来 表 示bool 类 型 只 有 true( 非 0 ) 和 f
20、alse( 0 ) 两 个 值C+编 译 器 会 在 赋 值 时 将 非 0 值 转 换 为 true, 0 值 转 换 为 false*/int main(int argc, char *argv) int a;bool b = true;printf(“b = %d, sizeof(b) = %dn“, b, sizeof(b);b = 4 ;a = b;printf(“a = %d, b = %dn“, a, b);1 4b = -4 ;a = b;printf(“a = %d, b = %dn“, a, b);a = 1 0 ;b = a;printf(“a = %d, b = %dn
21、“, a, b);b = 0 ;printf(“b = %dn“, b);system(“pause“);return 0 ;4 .8 三 目 运 算 符 功 能 增 强1 三 目 运 算 符 在 C 和 C+编 译 器 的 表 现int main() int a = 1 0 ;int b = 2 0 ;/返 回 一 个 最 小 数 并 且 给 最 小 数 赋 值 成 3/三 目 运 算 符 是 一 个 表 达 式 , 表 达 式 不 可 能 做 左 值(a 当 左 值 的 条 件 : 要 有 内 存 空 间 ; C+编 译 器 帮 助 程 序 员 取 了 一 个 地 址 而 已思 考 : 如
22、 何 让 C 中 的 三 目 运 算 法 当 左 值 呢 ?5 C/C+中 的 const1 const 基 础 知 识 ( 用 法 、 含 义 、 好 处 )int main()const int a;int const b;const int *c;int * const d;const int * const e ;return 0 ;Int func1 (const )初 级 理 解 : const 是 定 义 常 量 = const 意 味 着 只 读含 义 :/第 一 个 第 二 个 意 思 一 样 代 表 一 个 常 整 形 数/第 三 个 c 是 一 个 指 向 常 整 形 数
23、 的 指 针 (所 指 向 的 内 存 数 据 不 能 被 修 改 , 但 是 本 身 可 以 修 改 )/第 四 个 d 常 指 针 ( 指 针 变 量 不 能 被 修 改 , 但 是 它 所 指 向 内 存 空 间 可 以 被 修 改 )/第 五 个 e 一 个 指 向 常 整 形 的 常 指 针 ( 指 针 和 它 所 指 向 的 内 存 空 间 , 均 不 能 被 修 改 )Const 好 处/合 理 的 利 用 const,/1 指 针 做 函 数 参 数 , 可 以 有 效 的 提 高 代 码 可 读 性 , 减 少 bug;/2 清 楚 的 分 清 参 数 的 输 入 和 输 出
24、 特 性int setTeacher_err( const Teacher *p)Const 修 改 形 参 的 时 候 , 在 利 用 形 参 不 能 修 改 指 针 所 向 的 内 存 空 间2 C 中 “ 冒 牌 货 ”int main() const int a = 1 0 ;1 6int *p = (int*)printf(“a=%dn“, a);*p = 1 1 ;printf(“a=%dn“, a);printf(“Hellon“);return 0 ;解 释 :C+编 译 器 对 const 常 量 的 处 理当 碰 见 常 量 声 明 时 , 在 符 号 表 中 放 入 常
25、量 =问 题 : 那 有 如 何 解 释 取 地 址编 译 过 程 中 若 发 现 使 用 常 量 则 直 接 以 符 号 表 中 的 值 替 换编 译 过 程 中 若 发 现 对 const 使 用 了 extern 或 者 const int b = 2 ;1 7int arraya + b = 0 ;int i = 0 ;for(i=0 ; iage pT = t1printf(“t1 .age:%d n“, t1 .age); /3 5cout“b?/当 被 调 用 的 函 数 当 左 值 的 时 候 , 必 须 返 回 一 个 引 用 。 。 。 。 。j1 () = 1 0 0 ;
26、 /编 译 器 帮 我 们 打 造 了 环 境j1 ();*(j2 () = 2 0 0 ; /相 当 于 我 们 程 序 员 手 工 的 打 造 做 左 值 的 条 件j2 ();system(“pause“);返 回 值 是 形 参 , 当 引 用int g1 (int *p) *p = 1 0 0 ;return *p;intreturn *p;/当 我 们 使 用 引 用 语 法 的 时 候 , 我 们 不 去 关 心 编 译 器 引 用 是 怎 么 做 的/当 我 们 分 析 乱 码 这 种 现 象 的 时 候 , 我 们 才 去 考 虑 c+编 译 器 是 怎 么 做 的 。 。
27、。 。void main2 3 () int a1 = 1 0 ;a1 = g2 (int /用 引 用 去 接 受 函 数 的 返 回 值 , 是 不 是 乱 码 , 关 键 是 看 返 回 的 内 存 空间 是 不 是 被 编 译 器 回 收 了 。 。 。 。printf(“a1 :%d n“, a1 );printf(“a2 :%d n“, a2 );system(“pause“);2 5返 回 值 非 基 础 类 型struct Teachar char name6 4 ;int age;/如 果 返 回 引 用 不 是 基 础 类 型 , 是 一 个 类 , 那 么 情 况 非 常
28、 赋 值 。 。 涉 及 到 copy构 造 函 数 和 =操作 重 载 , 抛 砖 。 。 。 。struct Teachar char name6 4 ;int age;/如 果 返 回 引 用 不 是 基 础 类 型 , 是 一 个 类 , 那 么 情 况 非 常 赋 值 。 。 涉 及 到 copy构 造 函 数 和 =操作 重 载 , 抛 砖 。 。 。 。struct Teachar struct Teacher char name6 4 ;int age;int getTe(Teacher *myp ) Teacher *p = (Teacher *)malloc(sizeof(
29、Teacher);if (p =NULL) return -1 ;memset(p, 0 , sizeof(Teacher);p-age = 3 3 ;2 6*myp = p; /return 0 ;/指 针 的 引 用 而 已int getTe2 (Teacher* myp-age = 3 4 ;return 0 ;void main3 3 3 () Teacher *p = NULL;/getTe(getTe2 (p);printf(“age:%d n“, p-age);system(“pause“);2 常 引 用下 面 开 始 进 入 const引 用 难 点1 使 用 变 量 初 始
30、 化 const 引 用思 考 cost int ? ? ? ? 问 题 : const引 用 ,在 C+中 可 以 声 明 const 引 用const Typeconst int /int *p = (int *)b = 11; /err/*p = 11; /只 能 用 指 针 来 改 变 了2 7cout“aendl;printf(“a:%dn“, a);printf(“b:%dn“, b);printf(“printf(“system(“pause“);return 0;案 例 2:void main41()int a = 10;const int /const引 用 使 用 变 量
31、a初 始 化a = 11;/b = 12; /通 过 引 用 修 改 a,对 不 起 修 改 不 了system(“pause“);struct Teacher1char name64;int age;void printTe2(const Teacher1 *const pt)/const引 用 让 变 量 (所 指 内 存 空 间 )拥 有 只 读 属 性void printTe(const Teacher1 void main42() Teacher1 t1;t1.age = 33;printTe(t1);system(“pause“);2 82 使 用 字 面 量 常 量 初 始 化
32、const 引 用思 考 :1 、 用 变 量 对 const引 用 初 始 化 , const引 用 分 配 内 存 空 间 了 吗 ?2 、 用 常 量 对 const引 用 初 始 化 , const引 用 分 配 内 存 空 间 了 吗 ?void main() const int b = 10;printf(“b:%d“, /int 如 果 不 加 const编 译 失 败const int printf(“system(“pause“);3 综 合 案 例void main() /普 通 引 用int a = 1 0 ;int /常 量 引 用 : 让 变 量 引 用 只 读 属
33、性const int /常 量 引 用 初 始 化 分 为 两 种/1 用 变 量 初 始 化 常 量 引 用 int x = 2 0 ;const intprintf(“y:%d n“, y);/2 用 常 量 初 始 化 常 量 引 用 /int /引 用 是 内 存 空 间 的 别 名 字 面 量 1 0 没 有 内 存 空 间 没 有 方 法 做 引 用const int cout“hello.“endl;2 9system(“pause“);return ;3 const 引 用 结 论1 ) Const return a;intreturn a;int main() int a =
34、 g();intj() = 1 0 ;printf(“a = %dn“, a);printf(“b = %dn“, b);printf(“f() = %dn“, f();system(“pause“);return 0 ;3 07C+对 C 的 函 数 扩 展1 inline 内 联 函 数C+中 的 const 常 量 可 以 替 代 宏 常 数 定 义 , 如 :const int A = 3 ; #define A 3C+中 是 否 有 解 决 方 案 替 代 宏 代 码 片 段 呢 ? ( 替 代 宏 代 码 片 段 就 可 以 避 免 宏 的 副 作 用 ! )C+中 推 荐 使 用
35、 内 联 函 数 替 代 宏 代 码 片 段C+中 使 用 inline 关 键 字 声 明 内 联 函 数内 联 函 数 声 明 时 inline关 键 字 必 须 和 函 数 定 义 结 合 在 一 起 , 否 则 编 译 器 会 直 接 忽 略 内 联 请 求 。/宏 替 换 和 函 数 调 用 区 别#include “iostream“using namespace std;#define MYFUNC(a, b) (a) (b) ? (a) : (b)inline int myfunc(int a, int b) return a b ? a : b;int main() int
36、a = 1 ;int b = 3 ;/int c = myfunc(+a, b); /头 疼 系 统int c = MYFUNC(+a, b);printf(“a = %dn“, a);printf(“b = %dn“, b);printf(“c = %dn“, c);system(“pause“);return 0 ;说 明 1 :必 须 inline int myfunc(int a, int b)和 函 数 体 的 实 现 , 写 在 一 块说 明2C+编 译 器 可 以 将 一 个 函 数 进 行 内 联 编 译被 C+编 译 器 内 联 编 译 的 函 数 叫 做 内 联 函 数内 联 函 数 在 最 终 生 成 的 代 码 中 是 没 有 定 义 的C+编 译 器 直 接 将 函 数 体 插 入 在 函 数 调 用 的 地 方内 联 函 数 没 有 普 通 函 数 调 用 时 的 额 外 开 销 (压 栈 , 跳 转 , 返 回 )