1 / 107

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

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

guang
Download Presentation

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

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 清华大学计算机系列教材 殷人昆 陶永雷 谢若阳 盛绚华 编著 数据结构 (用面向对象方法与C++描述)

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

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

  4. C 语言是一个面向过程的语言。随着软件开发技术的进步, 程序员们最终发现, 把数据和施加在其上的操作结合起来,会得到更易于理解的程序,由此产生了面向对象的程序设计思想。 • 1980年代初,美国 AT & T 贝尔实验室的Bjarne Stroustrup设计并实现了C语言的扩充、改进版本,C++语言诞生了! • C++改进了C的不足之处,增加了对面向对象的程序设计的支持,在改进的同时,保持了C的简洁性和高效性。

  5. //一个简单的C++程序 /* 一个简单的C++程序,该程序在标准输出设备上输出一句问候语“hello” */ #include <iostream.h> int main() { cout << "hello!"; return 0;//正常返回 } • 这是一个只包含一个函数的程序,程序的基本元素是数据说明、函数和注释。

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

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

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

  9. C++源程序中还可包括各种编译命令, 这些命令被称为预处理指令, 常用的除 #include外, 还有条件预处理指令 #if、#ifndef 和#endif等和宏替换指令 #define。 • 预处理命令对编译器起作用, 它指示编译器在正式编译前做一些预先处理。#include命令将指示编译器将其后所跟的文件内容插入到当前文件中;#define定义一个常量或替换宏,它指示编译器在使用该常量或宏的地方替换为其实际内容;#if、#ifndef和 #endif指示编译器做条件编译。

  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);

  11. 函数原型 • 下面的程序给出了典型的 C程序结构,它是“Hello, 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( )的原型*/

  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( )的原型*/

  13. main(argc, argv)int argc;char *argv[ ];{printf("%s", hello("world"));} • 头文件名字的后缀用“.h”表示,程序文件名字的后缀用“.c”表示。 • hello.h:包含hello函数的原型。main函数可通过“# include”定向到该原型的定义文件,取得对原型的访问性。

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

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

  16. 现用 C++ 语句改写前面的 C 程序。 • C++ 程序在“.h”文件中对 hello( ) 使用了函数特征。对于 hello( ) 的原型: • 不要求形式参数的名字出现在特征中 • 参数的数目和类型,以及返回类型,都完整地在函数说明中定义 • C++允许在函数说明时, 在括号内直接声明形式参数的类型。

  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;}

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

  19. C++的数据声明 • C++的数据声明将数据名与数据类型联系起来。其主要形式有: • 常数值:如25, 13.4, “value is”, 它们的内容保持不变。 • 常量:数据声明时在变量名前冠以保留字const,如 const int MAX = 500, 可定义 一个常量。其内容在声明时给定,在声明它的程序运行时内容再赋值无效。 • 变量:数据类型的实例, 在程序执行时可以改变其内容。

  20. C++提供两大类数据类型:基本数据类型和复合数据类型。C++提供两大类数据类型:基本数据类型和复合数据类型。 • 基本数据类型有 5 种:整型(int)、浮点型(float)、字符型(char)、双精度浮点型(double)和无值(void)。 • 复合数据类型包括结构(struct)、联合(union)、位域、枚举(enum)、类(class)和用户自定义类型。 • 此外还有由基本数据类型和复合数据类型引申而来的数据类型,包括数组、指针、引用等。

  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的内容

  22. 引用:它用来给一个对象提供一个替代的名字。例如引用:它用来给一个对象提供一个替代的名字。例如 int i = 5; int& j = i; i = 7; printf (“i = %d, j = %d”, i, j ); 此时, j 是一个引用类型, 它代表i 的一个替代名。当 i 的值改变时, j 的值也跟着改变。当 printf 语句执行后, 打印出的 i 和 j 的值都是7。

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

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

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

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

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

  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

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

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

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

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

  33. 除简单语句外,C++还定义了一些可以控制程序执行流程的语句, 这些语句提供对控制流的分支和循环功能。 • C++中, 语句缺省都是顺序执行, 如果碰到分支或循环语句, 顺序执行的规则就要改变。此外,C++中还有一些跳转语句。 • 有时还有一些语句需要合在一起作为语法结构中的一条语句,这时需要将这些语句用大括号括起来,形成一个复合语句,复合语句不需要以分号终结。

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

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

  36. 例if ( ch >= '0' ) if ( ch <= '9' ) cout << “这是一个数字!”; else cout << “这不是一个数字!”; • 这时else 与哪个if 匹配呢?为解决语义上的这种歧义性,C++中规定,else总是与最后一个出现的还没有else与之匹配的if匹配,所以上面一句的else与第二个if匹配,如果程序员想让它与第一个if匹配,可以用大括号将不与else匹配的if语句括起来,使之成为复合语句。

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

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

  39. 当switch语句执行时, 先计算其后的表达式值, 将表达式的值与后面各 case 关键字后所跟选择常量依次比较。 • 如果与某一选择常量相等,则执行其冒号后跟的语句。如果和任何选择常量都不等, 则执行 default 子句后的语句(如果 default子句存在)或什么也不做(如果 default子句不存在)。 • 每个case子句都以break语句结束。break子句的作用是终止当前switch语句的执行。

  40. 例: 统计文章中各字母出现的次数。程序每读入一个字符ch, 根据它的值, 将相应的计数值增1, 假定英文大小写不区分。 intaCnt = 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; } 

  41. 循环语句 • 循环语句提供重复处理的能力, 当某一特定条件为 true时, 循环语句就重复执行, 并且每循环一次, 就会测试一下循环条件, 如果为false, 则循环结束, 否则继续循环。 • C++支持三种格式的循环语句:while、 do和 for语句。三者可以完成类似的功能,不同的是它们控制循环的方式。

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

  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); }

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

  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); }

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

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

  48. 例: 数组初始化 for ( inti = 0; i < size; i++ ) array[i] = 0; i = 0 False i < size True array[i] = 0 i++

  49. 跳转语句 • 除了顺序执行和分支、循环外, 有时需要中断一段程序的执行, 跳转到其它地方继续执行, 这时需用到跳转语句。 • 跳转语句包括break、continue和goto语句。 break语句 • break语句将使程序从当前的循环语句 ( do, while, for ) 内跳转出来, 接着执行循环语句后面的语句。Switch语句中也用到了break语句,这时它表示终止当前switch语句的执行,接着运行switch后的语句。

  50. continue语句 • continue语句也用于循环语句, 它不是结束循环, 而是结束循环语句的当前一次循环,接着执行下一次循环。在 while 和 do 循环中, 执行控制权转至对条件表达式的判断,在 for 循环中, 转去执行表达式2。 goto语句 • goto 语句无条件转移程序的执行控制,它总是与一标号(label)相匹配,其形式为: goto 标号;

More Related