清华大学计算机系列教材 殷人昆 陶永雷 谢若阳 盛绚华 编著

107
1 清清清清清清清清清清清 清清清 清清清 清清清 清清清 清清 清清清清 清清清清清清清清 C++ 清清

Upload: guang

Post on 16-Mar-2016

187 views

Category:

Documents


6 download

DESCRIPTION

清华大学计算机系列教材 殷人昆 陶永雷 谢若阳 盛绚华 编著. 数据结构 (用面向对象方法与 C++ 描述). 编程简介. C++. C++ 语言的概要 类、对象、构造函数与析构函数 输入 / 输出 函数、参数传递与函数返回值 函数名重载与操作符重载 动态存储分配 友元函数与内联函数 结构、联合与类. C++ 语言概要. C++ 源于 C 语言。 1970 年,两位程序员 Brian Kernighan 和 Dennis Ritchie 首创了一种新的程序设计语言,取名为 C 语言。 - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

1

清华大学计算机系列教材 殷人昆 陶永雷 谢若阳 盛绚华 编著

数据结构(用面向对象方法与 C++ 描述)

Page 2: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

C++语言的概要 类、对象、构造函数与析构函数 输入/输出 函数、参数传递与函数返回值 函数名重载与操作符重载 动态存储分配 友元函数与内联函数 结构、联合与类

Page 3: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

C++C++ 语言概要语言概要 C++C++ 源于源于 CC 语言。语言。 19701970 年,两位程序员年,两位程序员 Brian KernighanBrian Kernighan和和 Dennis RitchieDennis Ritchie 首创了一种新的程序设首创了一种新的程序设计语言,取名为计语言,取名为 CC 语言。语言。 设计设计 CC 语言的最初目的是编写操作系统。语言的最初目的是编写操作系统。由于其简单、灵活的特点,由于其简单、灵活的特点, CC 语言很快语言很快就被用于编写各种不同类型的程序,从就被用于编写各种不同类型的程序,从而成为世界上最流行的语言之一而成为世界上最流行的语言之一。

Page 4: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

C 语言是一个面向过程的语言。随着软件开发技术的进步 , 程序员们最终发现 , 把数据和施加在其上的操作结合起来,会得到更易于理解的程序,由此产生了面向对象的程序设计思想。 1980 年代初,美国 AT & T 贝尔实验室的Bjarne St

roustrup 设计并实现了C语言的扩充、改进版本,C++ 语言诞生了!

C++ 改进了 C的不足之处,增加了对面向对象的程序设计的支持,在改进的同时,保持了C的简洁性和高效性。

Page 5: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

// 一个简单的一个简单的 C++C++ 程序程序/* /* 一个简单的一个简单的 C++C++ 程序,该程序在标准输出设备上输出程序,该程序在标准输出设备上输出一句问候语“一句问候语“ hello” */hello” */#include <iostream.h>int main() {

cout << "hello!";return 0; //// 正常返回正常返回

}

这是一个只包含一个函数的程序,程序的基本元素是数这是一个只包含一个函数的程序,程序的基本元素是数据说明、函数和注释。据说明、函数和注释。

Page 6: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

注释注释 C++ 的第一次注释格式源于 C 语言。注释开始于“ /*” ,结束于“ */” ,在两者之间的任何内容,包括换行符都被编译器忽略。 注意注释符对不可以嵌套。 第一种注释符以“ //” 开头,它是单行注释符,在它同一行右侧的任何信息都将被认为是注释而由编译器略去。 注意:上面两种注释符的两个标志符 / 和 * , /和 / 之间不可以分开。

Page 7: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

#include #include 语句语句 C++ 将一些标准函数和变量说明放在头文件中。头文件中保存所有与标准函数或变量相关的信息,为了使用头文件中定义的变量和函数,必须将相应的头文件 include 进主程序,作为程序的一部分进行编译。 用户也可以定义自己的头文件,把一些相关的函数和变量组织在一个文件中,当另外的程序要用到这些函数和变量时,可以将该文件作为头文件 i

nclude 进来。

Page 8: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

#include#include 指令有两种格式:指令有两种格式: #include <#include < 头文件名头文件名 >> #include “#include “ 头文件名”头文件名” 第一种文件名在 第一种文件名在 <<>> 中指定中指定 , , 表示该文件表示该文件存放存放于系统设定的子目录中于系统设定的子目录中, 这类文件一般是由系统, 这类文件一般是由系统给出的给出的 , , 并已经过编译。并已经过编译。 第二种文件名在 第二种文件名在 ““”” 中给出,表示该文件 中给出,表示该文件存放存放在当前目录中在当前目录中 , , 这些头文件通常由用户自己给出。这些头文件通常由用户自己给出。 头文件中可包含其它头文件头文件中可包含其它头文件 , , 即 即 #include #include 可以直可以直接嵌套。接嵌套。

Page 9: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

C++ 源程序中还可包括各种编译命令 , 这些命令被称为预处理指令 , 常用的除 #include 外 , 还有条件预处理指令 #if 、 #ifndef 和 #endif 等和宏替换指令 #define 。

预处理命令对编译器起作用 , 它指示编译器在正式编译前做一些预先处理。 #include 命令将指示编译器将其后所跟的文件内容插入到当前文件中; #define 定义一个常量或替换宏,它指示编译器在使用该常量或宏的地方替换为其实际内容; #if 、 #ifndef和 #endif 指示编译器做条件编译。

Page 10: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

#define 用来定义一个常量或替换宏 , 如: #define size 20 //定义一个常量 size,其值永远为 20 #define MAX(x, y) ((x < y) ? y : x) //求 x, y中的最大值 经过预编译后 , 程序中所有出现 size 和 MAX(x, y) 之处都会被 20 和 ((x < y) ? y : x) 代替,如:

int array[size]; int i = MAX(4, 55); 经预编译后会变为 int array[20]; int i = ((4 < 55) ? 55 : 4);

Page 11: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

函数原型 下面的程序给出了典型的 下面的程序给出了典型的 CC 程序结构,它是程序结构,它是““ Hello, worldHello, world”” 程序的变型。程序的变型。 这个程序由三个文件组成:这个程序由三个文件组成: /* File: hello.h */ char *hello( );

/* File: hello.c */# include <stdio.h> /* 包括 sprintf ( ) 的原型 */# include <stdlib.h> /* 包括 malloc( ) 的原型 */# include <string.h> /* 包括 strlen( ) 的原型 */

# include "hello.h" /* 包括 hello( ) 的原型 */

Page 12: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

char *hello(name)char *name;{

char *value;   /* 返 回 串 "Hello, name.". */ value = (char *)(malloc(9+strlen(name)); sprintf (value, "Hello, %s.", name); return value;

}

/* File: main.c */# include <stdio.h> /*包括 printf ( )的原型 */# include "hello.h" /*包括 hello( )的原型 */

Page 13: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

main(argc, argv)int argc;char *argv[ ];{   printf("%s", hello("world"));}

头文件名字的后缀用“ .h” 表示,程序文件名字的后缀用“ .c” 表示。 hello.h :包含 hello 函数的原型。 main 函数可通过“ # include” 定向到该原型的定义文件,取得对原型的访问性。

Page 14: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

hello.c :这是 hello 函数的定义文件。它通过一个 string 类型的形式参数接受需要打印的 串 , 返回一个 string 类型的值作为打印串。返回类型必须与在 #include 定向的“ .h” 文件中所给出的原型的类型匹配。 main.c :这是打印“ Hello, world” 的主程序,它构造和返回一个欢迎词字符串,其结果通过函数 printf打印出来。 C 把函数和数据定义放在后缀为“ .c” 的代码文件中。在各代码文件中使用后缀为“ .h” 的

include 文件 , 定义对其他各模块的调用接口。

Page 15: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

C++的函数特征 特征是函数参数表的描述。 利用特征信息可进行严格的类型检查。它允许编译器检验实际参数的数目是否正确,对应的形参和实参是否相容,函数返回的类型与函数调用的环境是否相容。 它克服了在许多 C 程序的开发中,由于在 C 原型中没有定义参数的类型和数量,而造成的实参和形参之间不匹配,函数返回类型与使用之间不匹配等许多缺陷。

Page 16: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

现用 C++ 语句改写前面的 C 程序。 C++ 程序在“ .h”文件中对 hello( ) 使用了函数特征。对于 hello( ) 的原型 :

不要求形式参数的名字出现在特征中参数的数目和类型,以及返回类型,都完整地在函数说明中定义

C++允许在函数说明时 , 在括号内直接声明形式参数的类型。

Page 17: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

/* File: hello.h */char *hello(char *);

/* File: hello.cpp */# include <stdio.h> // 包含函数 sprintf( ) 的原型 # include <string.h> // 包含函数 strlen( ) 的原型# include “hello.h” // 包含函数 hello( ) 的原型char *hello(char *name) {  char *value = new char [9 + strlen(name)]; sprintf (value, "Hello, %s.", name);  return value;}

Page 18: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

/* File: main.cpp */# include <iostream.h> // 说明输出流对象 cout# include "hello.h" // 包含函数 hello( ) 的原型main(int argc, char *argv[ ]) {  cout << hello("world");}

Page 19: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

C++的数据声明 C++ 的数据声明将数据名与数据类型联系起来。其主要形式有:

常数值:如 25, 13.4, “value is”, 它们的内容保持不变。 常量:数据声明时在变量名前冠以保留字 const ,如

const int MAX = 500, 可定义 一个常量。其内容在声明时给定,在声明它的程序运行时内容再赋值无效。 变量:数据类型的实例 , 在程序执行时可以改变其内容。

Page 20: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

C++提供两大类数据类型:基本数据类型和复合数据类型。 基本数据类型有 5 种:整型 (int) 、浮点型 (float) 、字符型 (char) 、双精度浮点型 (double) 和无值 (voi

d) 。 复合数据类型包括结构 (struct) 、联合 (union) 、位域、枚举 (enum) 、类 (class) 和用户自定义类型。 此外还有由基本数据类型和复合数据类型引申而来的数据类型,包括数组、指针、引用等。

Page 21: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

枚举:是声明一个整型常数序列的方式。例如 , 在程序开头做如下声明 enum Boolean { FALSE, TRUE } 则建立一个Boolean类型。FALSE, TRUE 都是Boolean类型整型常数 , 默认值 0 和 1。 指针:存放对象的存储地址,例如

int i = 5; int *np; //np为一个指向整型量的指针 np = &i; //把整型变量 i 的地址赋给它 //np 成为指向整型变量 i 的指针 int k = *np; //k中存入 np所指地址 i的内容

Page 22: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

引用:它用来给一个对象提供一个替代的名字。例如 int i = 5; int& j = i; i = 7; printf (“i = %d, j = %d”, i, j ); 此时 , j 是一个引用类型 , 它代表 i 的一个替代名。当 i 的值改变时 , j 的值也跟着改变。当 p

rintf 语句执行后 , 打印出的 i 和 j 的值都是 7 。

Page 23: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

C++的作用域 在 C++ 中 , 每个变量都有一个作用域。区分一个变量时要同时考虑变量名及其作用域。 在函数定义中声明的变量 , 仅能在该函数内部有效使用 在类定义中声明的变量 , 仅能在该类内部有效使用 在一个段中声明的名字 , 也仅能在该段及其子段中有效使用。

Page 24: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

在整个程序各处都能访问的变量叫做全局变量。如果一个全局变量在文件 1 中声明,在文件 2 中使用,那么在文件 2中必须使用保留字 extern 对该变量进行声明。 如果在构成一个程序的两个文件中分别声明了两个同名的全局变量,这两个变量分别代表两个不同实体,此时需在两个文件中分别使用保留字 static 对变量进行声明。 如果一个段中的局部变量与一个全局变量同名,且还要在此段中使用该全局变量,此时需利用域操作符 ::访问该全局变量。

Page 25: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

表达式与操作符表达式与操作符 表达式是用来说明简单计算的。 C++ 中的表达式由操作数和操作符组成,它将操作符施加于操作数,最终得到一个结果。结果的数据类型由参加运算的数据类型决定。 a a + b * c + 200 2 * * R (x + y ) / (a – b ) 其中操作符执行的先后顺序由它们的优先级和结合性决定。

Page 26: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

C++提供了很多预定义的操作符,程序员也可以重新定义这些操作符。 算术操作符:算术操作符: + 、 -、 * 、 /、 %。其中 *、 /、 %优先于 +、 -。括号用来改变计算顺序。计算时,先计算括号内表达式的值,再将计算结果与括号外的数一起计算,如: 4 *( 1 + 2) = 4 * 3 = 12 取模操作符(%)用于计算两整数相除后得到的余数,如: 22 % 7 = 1 。 注意, %只能用于整数相除,不能对浮点数操作。

Page 27: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

赋值操作符 “ = ” 将其右侧的表达式求出结果 , 赋给其左侧的变量。例如: int Value; Value = (2 + 3) * 4; 赋值表达式运算的结果是右运算元的值 , 而结果类型是左运算元的数据类型 , 例如: Value = 2.8 * 4 // 结果为 11, 而不是 11.2 可以连续赋值 , 但必须保证各运算元的类型相同。它的处理结果是每个运算元的对象值都为最右侧的运算元值,例如: int i, j; i = j = 0; // i, j 都赋为 0

Page 28: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

复合操作符: 加 a += b 等价于 a = a + b 减 a -= b 等价于 a = a - b 乘 a *= b 等价于 a = a * b 除 a /= b 等价于 a = a / b 取模 a %= b 等价于 a = a % b 左移一位 a <<= b 等价于 a = a << b 右移一位 a >>= b 等价于 a = a >> b 按位与 a &= b 等价于 a = a & b 按位异或 a ^= b 等价于 a = a ^ b 按位或 a |= b 等价于 a = a | b

Page 29: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

自增,自减操作符自增,自减操作符 自增 (++), 自减 (--) : a++ 等价于 a = a + 1 a-- 等价于 a = a - 1 自增、自减符号既可位于变量的前面,也可位于变量的后面。前缀 ++ 表示先将其后的变量值增 1 ,然后将增 1后的变量参与表达式运算;而后缀 ++ 表示将其前面的变量先参与表达式运算,然后变量本身增 1 。 在单独作为一个表达式时, ++a 和 a++ 效果一样,都是将变量 a 自增 1 。 自减操作符含义类似。

Page 30: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

若自增 (++), 自减 (--) 符作为一个复杂表达式的一部分时,如: (a++) + b 和 (++a) + b 效果就不一样:在 a 、 b 初值均为 1 的条件下结果不同。

运 算 前 表 达 式 运 算 后 运算结果a b a b1 1 (++a)+b 2 1 31 1 (a++)+b 2 1 2

Page 31: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

条件操作符条件操作符 条件操作符是 C++ 中惟一的具有三个运算元的操作符,其形式为: 表达式 1 ? 表达式 2 : 表达式 3 它的运算方式为 : 先计算表达式表达式 1 的值 , 如果其值为非零 (true) ,则表达式表达式 2 的值就是整个表达式的最终结果 , 否则表达式表达式 3 的值就是整个表达式的值。常见的一个例子为: #define MIN (x, y) ((x < y) ? x : y) 上例定义了一个求两个数 x 和 y 中的最小值的宏 , 其中决定哪一个是最小值用了条件操作符。

Page 32: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

语句语句 语句是 C++ 程序中最小的可执行单元。一条语句由一个分号结束。 语句可以是简单语句,也可以是复杂语句。 int radius; 是声明语句; circum = 2 * PI * radius; 是表达式语句 ; 它由一个表达式后接一个分号形成。 cout << "hello, world"; cin >> Value; 等都是简单语句。这些语句告知计算机该如何定义变量以及如何执行程序。

Page 33: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

除简单语句外, C++还定义了一些可以控制程序执行流程的语句 , 这些语句提供对控制流的分支和循环功能。 C++ 中 , 语句缺省都是顺序执行 , 如果碰到分支或循环语句 , 顺序执行的规则就要改变。此外, C+

+ 中还有一些跳转语句。 有时还有一些语句需要合在一起作为语法结构中的有时还有一些语句需要合在一起作为语法结构中的一条语句,这时需要将这些语句用大括号括起来,一条语句,这时需要将这些语句用大括号括起来,形成一个形成一个复合语句复合语句,复合语句不需要以分号终结。,复合语句不需要以分号终结。

Page 34: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

if if 语句 语句 (( 二分支选择型二分支选择型 )) if 语句的一般格式为: if ( 条件表达式 ) 语句 ; 如果条件表达式的结果为 true (非零值 ),则执行语句语句,否则跳过这段语句。 语句可以有多条 , 这时需用大括号 { } 将这些语句括起来 , 形成一条复合语句。 if ( 条件表达式 ) { 语句 1; 语句 2; …… }

Page 35: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

如果希望在条件满足和不满足时分别执行不同语句,则用 else 引入条件不满足时的语句: if ( 条件表达式 ) 语句 1; else 语句 2; 语句 1 ,语句 2 也可以是复合语句,不过这时的语句不需以分号结尾。 语句 1 、语句 2 中又可以出现 if 语句,所以 if 语句可以嵌套,不过这时容易带来语义的歧义性。

Page 36: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

例例 if ( ch >= '0' ) if ( ch <= '9' ) cout << “这是一个数字!”; else cout << “这不是一个数字!”; 这时 else 与哪个 if 匹配呢?为解决语义上的这种歧义性,C++ 中规定, else总是与最后一个出现的还没有 els

e与之匹配的 if匹配,所以上面一句的 else与第二个 if匹配,如果程序员想让它与第一个 if匹配,可以用大括号将不与 else匹配的 if语句括起来,使之成为复合语句。

Page 37: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

if ( ch >= '0' ) { if ( ch <= '9' ) cout << “这是一个数字!”; } else cout << “这不是一个数字!” ; 条件表达式用于程序有分支语义的场合。 下例判断两个数是否从小到大排列,如果不是,则交换两个数: void swap ( int x1, int x2 ) { if (x1 > x2) { int temp = x1; x1 = x2; x2 = temp; } }

Page 38: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

Switch 语句 语句 (( 多分支选择型多分支选择型 )) switch 语句用于有多重选择的场合语句用于有多重选择的场合 , , 形式为形式为 switch ( 表达式 ) { case 值 1: 语句组 ; break; //break 可没有 case 值 2: 语句组 ; break; //break 可没有 …… case 值 n: 语句组 ; break; //break 可没有 default: 语句组 ; }; 注意 case后的数值必须是一个整型的常量表达式,且任意两个选择项不能相等。

Page 39: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

当 switch 语句执行时 , 先计算其后的表达式值 , 将表达式的值与后面各 case 关键字后所跟选择常量依次比较。 如果与某一选择常量相等,则执行其冒号后跟的语句。如果和任何选择常量都不等 , 则执行 defa

ult 子句后的语句 (如果 default 子句存在 ) 或什么也不做 (如果 default 子句不存在 ) 。 每个 case 子句都以 break 语句结束。 break 子句的作用是终止当前 switch 语句的执行。

Page 40: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

例 : 统计文章中各字母出现的次数。程序每读入一个字符 ch, 根据它的值 , 将相应的计数值增 1, 假定英文大小写不区分。

int aCnt = 0 , bCnt = 0 , … , zCnt = 0; switch (ch) { case 'a': case 'A': aCnt++; break; case 'b': case ’B': bCnt++; break; // case 'z': case ’Z': zCnt++; break; }

Page 41: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

循环语句循环语句 循环语句提供重复处理的能力 , 当某一特定条件为 true 时 , 循环语句就重复执行 , 并且每循环一次 , 就会测试一下循环条件 ,

如果为 false, 则循环结束 , 否则继续循环。 C++ 支持三种格式的循环语句: while 、

do 和 for 语句。三者可以完成类似的功能,不同的是它们控制循环的方式。

Page 42: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

While 语句 语句 ((先判断循环先判断循环 )) while 语句的一般形式为:

while ( 条件表达式 ) 循环体语句 while 循环先计算条件表达式 , 当条件表达式的运算结果为 true 时 , 就执行循环体语句。执行一次循环体语句后 , 就会重新计算条件表达式 , 当表达式的值为 false 时,循环结束。 while 循环可能一次也不执行。

Page 43: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

下列程序计算输入文件的字符数,并在标准输出上输出文件内容: #include <iostream.h> #include <fstream.h> main() { char ch; int count = 0; //字符数计数器 ifstream infile ("data.in", ios::in); while ( infile && infile.get (ch) ) { cout << ch; count++; } cout << "count : " << count; return (0); }

Page 44: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

do do 语句 语句 ((后判断循环后判断循环 )) do 语句的一般形式为: do 循环体语句 while (条件表达式 ); do 语句先执行循环体语句 , 然后计算条件表达式是否为 true, 如果是 , 则继续执行循环 , 否则结束循环。 与 while 语句不同的是, do 循环中的循环体语句至少执行一次 , 而 while 语句当条件第一次不满足时循环体语句一次也不执行。

Page 45: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

对字符计数的程序也可以用do语句实现。 # include <iostream.h> # include <fstream.h> int main() { char ch; int count = 0; //字符个数计数器 ifstream infile ("data.in", ios::in); if ( infile && infile.get(ch) ) { do { cout << ch; count++; } while ( infile && infile.get (ch) ); cout << "count : " << count; } return (0); }

Page 46: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

for 语句 for 语句用于预先知道循环次数的情况 , 其一般形式为: for ( 初始化语句 ; 表达式 1; 表达式 2 ) 循环体语句 ; 其中初始化语句可以是一条声明或表达式,用于对循环控制变量进行初始化或赋值。 表达式 1 用于控制循环结束 , 当它的值为 true 时 ,

继续循环 , 为 false 时终止循环。 表达式 2 在每次循环执行后改变循环控制变量的值。

Page 47: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

具体来说, for循环的执行过程为: 执行初始化语句; 计算表达式 1 的值; 如果表达式 1 的值为 true: 先执行循环体语句; 再执行表达式 2; 然后转向步骤; 如果表达式 1 的值为 false, 则结束循环。

Page 48: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

例 : 数组初始化 for ( int i = 0; i < size; i++ ) array[i] = 0;

array[i] = 0

i++

i < size

i = 0

True

False

Page 49: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

跳转语句跳转语句 除了顺序执行和分支、循环外 , 有时需要中断一段程序的执行 , 跳转到其它地方继续执行 , 这时需用到跳转语句。 跳转语句包括 break 、 continue 和 goto 语句。

break 语句语句 break 语句将使程序从当前的循环语句 ( do, while, f

or ) 内跳转出来 , 接着执行循环语句后面的语句。 Switch 语句中也用到了 break 语句,这时它表示终止当前 switch 语句的执行,接着运行 switch后的语句。

Page 50: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

continue 语句语句 continue 语句也用于循环语句 , 它不是结束循环 , 而是结束循环语句的当前一次循环结束循环语句的当前一次循环,接着执行下一次循环。在 while 和 do 循环中 , 执行控制权转至对条件表达式的判断,在 for 循环中 , 转去执行表达式 2 。

goto 语句 goto 语句无条件转移无条件转移程序的执行控制,它总是与一标号( label)相匹配,其形式为: goto 标号 ;

Page 51: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

标号是一个用户自定义的标识符 , 它可以处于 goto 语句的前面,也可以处于其后面,但是标号必须与 goto 语句处于同一个函数中。 标号定义时,由一个标识符后面跟一冒号组成,如: goto next; …… next: 语句 // 标号

Page 52: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

下面程序要从键盘读入用户输入的数 , 对其求和 , 当用户输入数 0时 , 表示输入结束。 #include <iostream.h> int main() { int sum = 0; int iVal; while (1) { //永远循环 cout << “请输入一个整数或 0:”; cin >> iVal; if ( iVal == 0 ) break; //循环出口 sum += iVal; } cout << ”The sum : ” << sum << ‘\n’; return 0; }

Page 53: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

下面程序对用户输入的所有正数求和 , 如果输入的是负数 , 则忽略该数。 int sum = 0; int iVal = 1; while ( iVal != 0) { cout << " 请输入一个整数或 0:"; cin >> iVal; if ( iVal < 0 ) continue; sum += iVal; } cout << “The sum: ” << sum << ‘\n’;

Page 54: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

C++的类 C++ 的核心部分是类的定义。类定义体现了抽象数据类型的思想。为达到信息隐蔽的原则。规定对类的成员有三级存取:

共有 (public)私有 (private) 保护 (protected)

在 public 域中声明的数据成员和函数成员( 成员函数 ) ,程序中其它类的对象或操作都能请求该类的对象执行它们,因此这些数据成员和成员函数构成类的界面部分。

Page 55: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

在 private域和 protected域中声明的数据成员和成员函数构成类的私有部分,只能由该类的对象和成员函数,以及声明为友元 (friend)的函数或类的对象才能访问它们。 在 protected域中声明的数据成员和成员函数,还允许该类的派生类访问它们; 在 private域中声明的数据成员和成员函数,则不允许该类的派生类访问它们。 下面给出一个 point 类的声明。Point 类中 点的表示由两个整数变量 x, y 组成。类的用户不能直接访问它们。

Page 56: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

#ifndef POINT_H#define POINT_H //In the header file point.hclass Point { // 类定义private: // 私有域 int x; // 数据成员:点坐标 int y;public: // 共有域 Point ( int, int ); // 构造函数 Point ( Point & ); // 复制构造函数 ~Point ( ); // 析构函数 int get_x ( ); // 取 x 坐标 int get_y ( ); // 取 y 坐标

Page 57: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

Point operator + ( point ); // 点加点 Point operator / ( int ); // 点除整数 Point operator * ( int ); // 点乘整数 int operator > ( Point ); // 点比较 int operator < ( Point ); // 点比较 int operator == ( Point& ); // 点比较 friend istream& operator >> ( istream&, Point& ); // 输入友元函数 friend ostream& operator << ( ostream&, Point& ); // 输出友元函数};#endif

Page 58: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

   为了存取一个点的 x, y 分量 , 类提供了两个函数 get_x, get_y 。这样可用 private域来保护数据的表示 , 防止类的用户直接使用数据的内部表示来编写代码,通过使用存取函数来操作数据来维持类的抽象性。 private 是声明默认的存取级别。 系统开发时 , 把类的声明放在头文件中 , 成员函数的实现放在源程序文件中。在源程序文件中函数的实现通过作用域设定命令“ ::” 而被归属到某一个类。

Page 59: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

     例,对于 Point 类的输出友元函数的实现可以在源程序文件中给出,形为: ostream & operator << (ostream& strm, Point p) { return strm << "(" << p.get_x ( ) << "," << p.get_y () << ")"; }这个函数把点 p 的值以“ x, y” 的格式送到 strm 指明的输出流中去。

Page 60: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

C++中的对象 建立类的对象 (亦称为实例化 ) 时采用的方式类似于定义 C 变量的方式,可以自动地,或静态地 , 或通过动态分配来建立。建立一个 Point 类实例的语句是:

Point p (6, 3); 自动地 Point q; 自动地 static Point s (3, 4); 静态地 Point *t = new Point(1, 1); 通过动态分配

对象 p 、 q 和 s 都是 Point 类的对象。

Page 61: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

构造函数 当遇到以上的每一个语句时 , 将隐式地调用一个构造 (constructor) 函数 , 这个构造函数属于一个与它同名的类。 在 Point 类的定义中声明了两个构造函数 , 构造函数的参数用于初始化表达式的值。 例如 , 当使用声明 Point p(6, 3) 建立 Point 类的对象 p 时 ,调用了构造函数 Point (int, int);通过以下函数定义 , 将其 x, y 分量设定为 6, 3 : Point :: Point (int a,int b) { x = a; y = b; } Point :: Point (int a,int b) : x(a), y(b) { }

Page 62: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

构造函数可以定义默认值。例如 Point :: Point ( int a = 0, int b = 0 ) : x(a), y(b) { } 当定义实例时给定初始值 , 则该实例以给定初始值来初始化其数据成员。 Point p(6, 3); 则有 x = a = 6, y = b = 3 当定义实例时未给出初始值。则该实例以默认值来初始化其数据成员。 Point q; 则有 x = a = 0, y = b = 0

Page 63: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

析构函数 当要放弃对象时 , 需隐式地调用另一个函数 ,叫做析构 (d

estructor) 函数 , 它属于名字相同的类 , 但在名字前面加上了一个“~”。例如 ~ Point 。 为一个类可定义几个构造函数,但只能定义 一个析构函数。当控制要退出自动变量的作用域时 , 或当通过 del

ete 命令释放一个动态分配的变量时 , 就要调用析构函数。当 main 函数执行结束时,将释放静态声明的变量。 一个析构函数用于在删除一个类的对象时做清除工作。

Page 64: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

C++的输入 /输出 在 C++ 中执行输入 / 输出操作 , 需用 #include预处理指令包括一个 <iostream.h> 头文件。用它可支持 C++的流 (stream) 操作。 “流”是个简单的字符序列。在 C++ 中有两个预定义的类 istream 和 ostream ,它们定义了输入流和输出流。 基本输入 / 输出方式:

键盘屏幕输入 / 输出; 文件输入 / 输出。

Page 65: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

键盘屏幕输入 /输出 在 C 中有用于定向到键盘输入设备、屏幕输出设备和错误文件的命令 stdin 、 stdout 和 stderr 。 在 C++ 中用 cin , cout 和 cerr 来定义键盘输入类、屏幕输出类和错误信息输出类。 操作符 << 用于写出类 ostream 的一个对象,对于一系列输出对象,可用 << 分开。 操作符 >> 用于读入类 istream 的一个对象。

Page 66: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

在下面程序中使用了流 cin >>,相继从标准输入设备上输入两个整型变量a和b, 并将它们打印到标准输出设备上。

在输出语句中最后输出的endl是C++的I/O操作符 , 它的用途是输出一个换行符并清空流。

#include <iostream.h>void main ( ) { int a, b; cin >> a >> b; cout << ”a : " << n << "f : " << f << endl;}

Page 67: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

C++ 中的输入 / 输出可以是自由格式,程序员不需要使用格式化符号来指定输入 /输出项的类型和顺序。 与其它 C++ 操作符一样,输入 / 输出操作符能够被重载。

Page 68: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

文件输入 /输出 C++ 中的文件输入 / 输出方式如下所示。 在程序开头必须用预处理指令 #include 包含头文件 <fstream.h> ,它定义了类 ifstrea

m 、 ofstream 和 fstream 。 要创建一个输入流 , 必须声明它为 ifstrea

m 类的实例。 要创建一个输出流 , 必须声明它为 ofstrea

m 类的实例。 执行输入和输出操作的流必须声明它为 fs

tream 类的实例。

Page 69: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

#include <fstream.h>#include <iostream.h>#include <stdlib.h>void main ( ) { ifstream inFile; //inFile 为输入流对象 ofstream outFile; //outFile 为输出流对象 outFile.open ( "my.dat", ios :: out );

// 建立输出文件 my.dat char univ[ ] = Tsinghua, name[10]; int course = 2401, number; outFile << univ << endl; // 输出到 my.dat outFile << course << endl;

Page 70: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

inFile.open("my.dat", ios::in | ios::nocreate); // 打开输入文件 my.dat if ( !inFile ) { cerr << “ 不能打开 my.dat” << endl; exit(1); } char c; inFile >> name >> c >> number; outFile << "name: " << name << endl; outFile << "number: " << number << endl;}

Page 71: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

ifstream 类、 ofstream 类和 fstream 类都是从 istream 类和 ostream 类派生出来的,而类 istream 和 ostream又是从类 ios派生出来的,因此这些类都可使用类 ios 的所有运算。 在调用打开文件函数 open( ) 时 , 函数参数表包括实际文件名和数据流动的方向,函数返回文件的开始地址。系统在存储文件时 , 在其末尾添加有文件结束标记。 如果文件未被打开 , 则 outFile = 0; 如果文件被成功地打开 , 则它将代替 cout, 将输出引导到文件 my.dat 中。

Page 72: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

在文件打开的操作中,指定的文件模式有以下几种: iso::app :把所有对文件的输出添加在文件尾。它只用于输出文件。 iso::binary :文件以二进制方式打开。此项缺省时文件以文本方式打开。 iso::nocreate :若文件不存在则将导致打开操作失败。 iso::out :表明该文件用于输出。此项可缺省。 iso::in :表明该文件用于输入。此项可缺省。

Page 73: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

C++中的函数 在 C++ 中有两种函数: 常规函数和成员函数。 不论哪种函数 , 其定义都包括 4 个部分 : 函数名、形式参数表、返回类型和函数体。 函数的使用者通过函数名来调用该函数;调用时把实际参数传送给形式参数表作为数据的输入;通过函数体中的处理程序实现该函数的功能;最后得到返回值作为输出。

Page 74: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

下面给出一个函数的例子。max 是函数名 , int a 和 int b 是形式参数表 , 函数名前面的 int 是返回类型 , 在花括号内括起来的是函数体 , 它给出了函数操作的实现。 int max ( int a, int b ) { // 函数返回 a 与 b 中的大值 if (a > b) return a; else return b;}

在 C++ 中所有函数都有一个返回值,或者返回计算结果,或者返回执行状态。

Page 75: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

如果函数不需要返回值 , 可使用 void 来表示它的返回类型。函数的返回值通过函数体中的 return 语句返回。 return 的作用是返回一个与返回类型相同类型的值,并中止函数的执行。 函数返回时可以通过引用方式,参看下面程序 , 此时在函数类型后面加上一 个“ &” 。 #include <iostream.h>

char& replace(int m);char s[80] = “Hello There”;

Page 76: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

main ( ) { replace(5) = ‘x’; cout << s;

// 用 x 代替 Hello 后面的空格}

char& replace ( int m ) { return s[m]; }

函数 replace( ) 的返回类型说明为返回一个字符的引用类型 , 在函数执行时返回参数 m 指定的 s 数组元素的值。 main ( )执行时把字符 “ x” 送给 s[5] 。

Page 77: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

C++中的参数传递 函数调用时传送给形参表的实参必须与形参在类型、个数、顺序上保持一致。 参数传递有两种方式。一种是传值,这是缺省的参数传递方式 ; 一种是引用类型。 使用传值方式时,把实参的值传送给函数局部工作区相应的副本中,函数使用这个副本执行必要的功能。这样,函数修改的是副本的值,实参的值不变。

Page 78: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

使用引用类型方式传递时 , 需将形参声明为引用类型,即在参数名前加一个“ &” 。参看下面的程序示例。 当一个实参与一个引用型形参结合时,被传递的不是实参的值,而是实参的地址,函数通过地址存取被引用的实参。函数执行后实参的值将发生改变。 当一个函数的返回值多于一个时 , 其中一个可由 retu

rn 语句返回 , 其它返回值可使用引用型参数返回。#include <iostream.h>void swap (int& i, int& j);

Page 79: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

main ( ) { int a = 1, b =2; cout << "a and b: " << a << " " << b << "\n"; swap ( a, b ); // 调用时实际参数不需要加 & cout << "a and b: " << a << " " << b << "\n";}

void swap ( int& i, int& j ) {// 对换 i 与 j 的内容 int t = j; j = i; i = t;// 不需要加 *}

Page 80: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

一种特殊的引用调用方式叫做常值引用 , 其格式为 const Type& a ,其中 Type 为参数的数据类型。在函数体中不能修改常值参数。

一种特殊情况是数组参数的传递。数组作为形参可按传值方式声明,但实际采用引用方式传递,传递的是数组第一个元素的地址。在函数体内对形参的数组所做的任何改变都将反映到作为实参的数组中。 此外,在参数表中一般按形如 int R[ ] 的形式声明,因此需要显式地声明数组的大小。

Page 81: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

若传送的值参是一个对象 ( 作为类的实例 ) 时 , 在函数中就创建了该对象的一个副本。在创建这个副本时不调用该对象的构造函数,但在函数结束前要调用该副本的析构函数撤消这个副本。 若采用引用方式传递对象,在函数中不创建该对象的副本,也不存在最后撤消副本的问题。但是,通过引用传递的是对象时,函数对对象的改变将影响调用的对象。

Page 82: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

成员函数的返回值 当成员函数的返回值为传值方式时 , 允许改变该对象的私有数据成员。 当成员函数的返回值为常值传值方式时 , 需加 const 标识 , 该对象的私有成员不能改变。 当成员函数的返回值为引用方式时 , 该成员函数的返回值应是一个已存在变量 ( 或对象 )的别名。当该成员函数被重新赋值时 , 其对应变量 ( 或对象 ) 的值将改变。 当成员函数的返回值为常值引用方式时 , 其返回值与引用方式的成员函数返回值类同。但该成员函数不能改变该对象的私有成员。

Page 83: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

当成员函数返回值为常值传值方式或常值引用方式时 , const 标识符一般放在最后。 #include<iostream.h> class Temperature { private: float highTemp, lowTemp; //数据成员 public: Temperature(int hi, int lo) //构造函数 { highTemp = hi; lowTemp = lo; } void UpdateTemp(float temp); //传值返回 float GetHighTemp( ) const; //常值返回

Page 84: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

float GetLowTemp( ) const; // 常值传值返回};void Temperature :: UpdateTemp(float temp) { if (temp > highTemp) highTemp = temp; if (temp < LowTemp) LowTemp = temp;}float Temperature :: GetHighTemp( ) const { return highTemp;}float Temperature :: GetHighTemp( ) const { return highTemp;}

Page 85: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

C++中的函数名重载 函数名重载允许 C++ 程序中多个函数取相同的函数名 , 但其形参或返回类型可以不同。 例如, C 标准函数库中有 3 个标准函数 abs( ) 、

labs( ) 和 fabs( ), 分别计算整型数、长整型数和双精度型数的绝对值。在 C 中因处理的数据类型不同 , 必须取不同的函数名。在 C++ 中 , 可以把这 3 个函数都命名为 abs ( ) : int abs ( int ); long abs ( long ); double abs ( double );

Page 86: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

C++ 的操作符重载 C++提供了一种能力 , 可用同一个名字定义多个函数 , 这种能力叫做操作符重载。 例如 , 可以命名一个函数 : clear(* int), 它将一个整数清零。还可以再命名另一个函数 clear(int[ ]) ,它把一个整数数组清零。

编译器能够比较具有同名的函数的特征 , 通过识别实参的数目和每个实参的类型 , 来标识使用于一个特定调用的是哪一个版本的 abs( ) 。 

Page 87: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

在 C 中 , 必须使用名字 clearIntArray( ) 和clearInt( ) 来区分这两个函数。在 C++ 中,编译器能够比较同名函数的特征 , 通过识别实参的数目和每个实参的类型 , 来标识一个特定调用中用的是哪一个版本的 clear 。

为了支持面向对象, C++ 提供了双目重载操作符 (如‘+’和‘<’ ) 。这种操作可使得程序更可读、写得更自然。 例如 , 可定义“点 (Point)” 的运算 , 像

p1+p2: 把两个点 (x1, y1) 和 (x2, y2) 相加成一个点 (x1+x2, y1+y2) 。

Page 88: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

p1<p2: 两个点 p1 和 p2 的“小于”关系 , 表示 p1比 p2 更靠近原点 (0, 0) 。 p1/ i: 一个点 p= (x, y) 除以一个整数

i 的除法 (x/i, y/i) 。 可以按以下方式使用重载操作: Point operator + ( Point p ); Point operator / (int i);

int operator < (Point p); 使用这些新的操作的表达式如 : Point midPoint = (point1+ point2) / 2;或 if ( midPoint < referencePoint ) ...

Page 89: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

注意 : 每一个这样的操作符在调用时可看成是该操作符左边对象的成员函数。 例如 , (point1+point2) 实际上是一个消息。由类 Point的实例 point1调用成员函数“ +”, 该对象的属性确定第一个操作数的值。 函数参数表中指定的 Point 的实例 point2 的属性确定第二操作数的值。 这种重载能力允许像使用内建类型 (如 int , float) 那样来使用用户自定义类型。与在不允许重载操作的语言中相同的语句比 , 这样可以改善程序的可读性。

Page 90: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

C++ 的动态存储分配 在 C 程序中 , 使用一个函数 malloc, 为程序分配它所需要的空间,一旦程序执行结束需要返回到它的调用者时,必须释放这个空间。 C++ 为动态存储分配提供了两个新的命令:

new 和 delete 。它们可用于取代 C 中的库函数 malloc 和 free 。 在 C++ 中没有无用单元收集,使用 new 分配的存储必须显式地使用 delete 释放。

Page 91: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

操作 new 要求以被建立对象的类型做为参数,并返回一个指向新分配空间的指针。 作为对比 , 在 C 中 , 函数 malloc 要求它的调用者提供所需存储空间的数量。 例如 , 为动态分配一个整数或一个点 , 可编写如下语句: int *ip = new int;或 或 Point *p = new Point; 它们组成了指针变量的声明 (如 * name) 和动态存储分配 ( new 类型 ) 。

Page 92: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

Delete 命令必须能够知道 new 分配了多少存储。当要释放动态分配的数组时,必须告诉 delete 该数组中包含的元素个数。 例如,如果已建立下列有 100个点的数组: Point* p = new Point[100]; 则通过以下命令释放该存储 : delete [100]p; 若遗漏了“ [100]”, 则将只释放 p 所指示的第一个元素 , 将“失去”其它 99个点所占据空间 , 以致不能再复用它们。若使用时元素下标超出 100, 程序将会出错且结果不可预测。

Page 93: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

友元 (friend) 函数• 在类的声明中可使用保留字 friend 定义友元函数。• 友元函数实际上并不是这个类的成员函数,它可以是一个常规函数,也可以是另一个类的成员函数。如果想通过这种函数存取类的私有成员和保护成员,则必须在类的声明中给出函数的原型,并在该函数原型前面加上一个 friend 。• 参看 Point 类的声明 , 有两个重载操作符 << 与 >

> ,它们都被声明为友元函数。

Page 94: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

内联 (inline) 函数 在函数定义前加上一个 inline前缀就成为内联函数。编译程序在编译时将会把这个函数语句直接插入到普通代码中,因而减少了与函数调用和参数传递有关的系统开销。 直接插入代码所需要的空间比不直接插入的调用方式所需要的空间要多,这取决于函数定义的大小。 除了加上 inline 保留字外 , 内联函数的定义 与其它任何函数定义的方式一样。 inline Point operator + (Point p);

Page 95: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

结构 (struct) 与类 C++ 扩充了 C 中结构 (struct) 型的功用 , 加进成员函数以说明一个类 (class) 。在 C++ 中 struc

t 与 class 的区别在于 : 在 struct 中 , 默认的访问级别是 public 。若在 s

truct 内部自始至终缺省访问级别 , 则所有的成员都是共有的。 在 class 中 , 缺省的访问级别是 private 。 除此之外, struct 与 class 是等价的。例如,下面给出定义矩形类的三种等价的类声明。

Page 96: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

class Rectangle { int x1, y1, h, w;public: Rectangle ( ); ~Rectangle ( ); int GetX ( ); int GetY ( ); void SetX (int x); void SetY (int y); int GetHeight ( ); int GetWidth ( ); …………}

Page 97: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

struct Rectangle { Rectangle ( ); ~Rectangle ( ); int GetX ( ); int GetY ( ); void SetX (int x); void SetY (int y); int GetHeight ( ); int GetWidth ( ); …………private: int x1, y1, h, w;}

Page 98: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

联合 (Union) 与类 与结构一样 , 用 Union 也可以定义类。 在 C++ 中 , Union 可包含函数和变量 , 还可包含构造函数和析构函数。 C++ 的 Union 保留了所有 C 的特性 , 主要是让所有的数据成员共享相同的存储地址。 与 class 和 struct 相比 , Union 可节省存储。与结构相似 , Union 中默认存取级别是 public 。

Page 99: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

模板 模板 (template)(template)

定义定义 适合适合多种数据类型多种数据类型的的类定义类定义或或算法算法,,在特定环境下通过简单地代换,变成在特定环境下通过简单地代换,变成针对具体某种数据类型针对具体某种数据类型的的类定义类定义或或算算法。法。

Page 100: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

用模板定义用于排序的数据表类用模板定义用于排序的数据表类#include <iostream.h> template <class Type> class dataList { private: Type *Element; int ArraySize; void Swap (int m1, int m2); int MaxKey (int low, int high);

Page 101: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

public: dataList (int size = 10) : ArraySize (size), Element (new Type [Size]) { } ~dataList ( ) {delete [ ] Element;} void Sort ( ); friend ostream& operator << (ostream& outStream, datalist<Type>& outList); friend istream& operator >> (istream& inStream, datalist<Type>& inList); }

Page 102: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

类中所有操作作为模板函数的实现类中所有操作作为模板函数的实现#include “datalist.h” template <class Type> void dataList <Type> :: Swap (int m1, int m2) { // 交换由 m1, m2 为下标的数组元素的值 Type temp = Element [m1]; Element [m1] = Element [m2]; Element [m2] = temp; }

Page 103: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

template <class Type> int dataList<Type>:: MaxKey (int low, int high) { // 查找数组 Element[low] 到 Element[high] // 中的最大值,函数返回其位置 int max = low; for (int k = low+1, k <= high, k++) if ( Element[max] < Element[k] ) max = k; return max; }

Page 104: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

template <class Type> ostream& operator<< (ostream& OutStream, dataList<Type> OutList) { OutStream << “ 数组内容 : \n”; for (int i = 0; i < OutList.ArraySize; i++) OutStream << OutList.Element[i] << ‘ ’; OutStream << endl; OuStream << “ 数组当前大小 : ” << OutList.ArraySize << endl; return OutStream; }

Page 105: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

template <class Type> istream& operator >> (istream& InStream, dataList<Type> InList) { cout << “ 录入数组当前大小 : ”; Instream >> InList.ArraySize; cout << “ 录入数组元素值 : \n”; for (int i = 0; i < InList.ArraySize; i++) { cout << “ 元素” << i << “:” ; InStream >> InList.Element[i]; } return InStream; }

Page 106: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

template <class Type> void dataList<Type>::Sort ( ) { //// 按非递减顺序对按非递减顺序对 ArraySizeArraySize 个关键码个关键码 //Element[0]//Element[0] 到到 Element[ArraySize-1]Element[ArraySize-1] 排序排序 for ( int i = ArraySize -1; i > 0; i-- ) { int j = MaxKey (0, i); if ( j != i ) swap (j, i); } }

Page 107: 清华大学计算机系列教材      殷人昆 陶永雷  谢若阳  盛绚华  编著

使用模板的选择排序算法的主函数使用模板的选择排序算法的主函数 #include “selecttm.h” const int SIZE = 10; int main ( ) { dataList <int> TestList (SIZE); cin >> TestList; cout << TestList << endl; TestList.Sort ( ); cout << TestList << endl; return 0; }