• 1. The C++ Programming Language Chapter 1
  • 2. C++ Programming in UNIX课程介绍 C++ 语法基础 面向对象程序设计的概念 大量的编程实践 目标 熟练掌握C++语法 具有面向对象程序设计的概念与能力 能熟练阅读复杂的C++程序源代码 能独立的设计与完成面向对象的C++程序
  • 3. 课程内容简介 1C++语言基础 保留字 变量,常量 表达式 语句 函数 程序的结构 数据结构与算法 数组、指针、引用、结构、链表与栈
  • 4. 课程内容简介 2C++面向对象编程 类 构造函数与析构函数 静态成员与友员 函数重载 继承与多态 I/O流 模板 异常
  • 5. 程序设计语言介绍1What computer understand? bits Assembler Language Limited structure Global scope Machine code Primitive High-Level Language Function decomposition Data separation High level structure
  • 6. 程序设计语言介绍2Block Structured Language Encapsulation Flexible data scoping Modularization Object-Oriented Language Inheritance Polymorphism Abstract data types
  • 7. C++程序设计语言1972,AT&T, Bell Lab. Dennis Ritche, C language 1980, Bell Lab. Bjarne Stroustrup, C extension, 1983, C++ named 1997, ANSI (American National Standards Institute) C++ (standard C++)
  • 8. What C++ will we learn in this course ?Standard C++: ANSI C++ is more scalable to different platform such as Unix, Microsoft windows, Mac… The standard C++ library got supported by most of industry providers. You’d better don’t know C. ........??? We will try to avoid C library and C syntax. A C++ file can be with .cc, .cp, .cpp extensions.
  • 9. 为什么选标准 C++ANSI 规范了C++的标准, 使之具有高度的可移植性。 C++ 程序能够运行得很快,可直接操作系统资源,保持机器层次的实现细节。 C++ 不要求图形环境, 对系统要求相对较低。 易于解决与旧工程的接口以及在数据库,存储和性能方面的技术限制。 C++ 是一种面向对象的多范型语言,可以将面向对象的模型映射成为C++ 的结构。它为开发者设计和编写一个解决方案提供了一定的选择范围。
  • 10. C++的优点Supports data abstraction and object-oriented programming Contains all existing features of C, making the migration from C to C++ relatively easy Is as portable and efficient as C Can be linked to existing C libraries and functions Provides strong static-type checking Is a general-purpose language
  • 11. 程序员应该具备的计算机知识1操作系统与应用程序 运行环境与运行机制 系统与命令 运行环境与命令行参数 进程 栈 堆
  • 12. Binary and HexadecimalBinary: 0101 1000 Decimal: 88 Hexadecimal: 0x58 1 byte = 8 bits.0123456789ABCDEF0123456789101112131415
  • 13. 程序员应该具备的计算机知识2编辑器 编译器 编译器的功能 解释执行与编译执行的差别 熟悉自己常用的编译器,查错能力 连接器 库与库函数 系统调用
  • 14. 软件开发周期源程序编辑编译连接调试运行
  • 15. Software Lifecycle开发 测试 维护 更新
  • 16. 熟悉你的环境可用的UNIX服务器 www.openlab.com.cn 192.168.0.21 192.168.0.23 192.168.0.26 Telnet命令介绍: telnet 192.168.0.21 Login: use your registered user account. Password: type in your pass word.
  • 17. 创建自己的学习帐号telnet www.openlab.com.cnlogin: tarena Password: tarena 欢迎使用达内科技(中国)公司开放实验室的服务! Welcome to the OpenLab of Tarena Technologies Inc. Cananda. 请按照以下提示创建您的用户帐号. Please follow the steps to create your own account. (请输入您要注册的帐号)Please enter your new account name:XXXXXXXX (请输入您的E-Mail地址)Please enter your email address: XXX@YYY.ZZZ
  • 18. 用自己的帐号登录UNIX服务器Escape character is '^]'. SunOS 5.8 login: XXXXXXX Choose a new password. New password: *******
  • 19. 程序员经常用到的UNIX命令1简单的文件维护与管理 ls, cd, mkdir, rm, cp, mv, cat, more 源程序的编写 vi, ed 编译与连接 gcc, g++, ld 运行与调试 adb,gdb
  • 20. 程序员经常用到的UNIX命令2查看运行状态 % ps –ef % grep aaa a.txt (aaa is the chars in the file name a.txt) % prstat (ctrl D to exit) % kill pid (pid is a process id)
  • 21. 第一个UNIX上的C++程序用vi编辑器来编写hello.cc源程序 % vi hello.cc/*the first C++ program*/ #include using namespace std; //main function int main() { cout << "Hello world!" << endl; cout << "This is my first C++ program.\n"; }
  • 22. g++的常用参数- c 编译成目标文件.o - o指定输出文件名,输出文件名跟在-o后面,用空格分隔。如果不使用这个选项,缺省的输出文件名为a.out。 - g产生有调试信息的可执行文件 - w不产生警告信息 - l 连接指定的库文件 - L指定库文件的路径 - i 要包含的头文件 - I 头文件的路径 - E 显示预处理后的程序文件到屏幕上,可以用-o指定输出到文件 - S 产生汇编程序 如果没有c、E、S就会生成可执行文件
  • 23. 编译hello.cc% g++ -c hello.cc % ls
  • 24. 连接hello.o% g++ -o hello hello.o % ls % g++ hello.o % ls
  • 25. 运行hello 程序% hello % a.out
  • 26. C++程序的基本结构1/*the first C++ program*/ #include using namespace std; //main function int main() { cout << "Hello world!" << endl; cout << "This is my first C++ program.\n"; }
  • 27. C++程序的基本结构2#include< > 与 #include" " Name space: 提供了一个全局标识符和全局变量所在的作用域。 int main() 注释 函数 函数的调用 cout语句
  • 28. 头文件#include语句 #include < > 与 #include " "使用 #include using namespace std; 少用 #include
  • 29. Main函数main函数的作用 Standard C++ main( )格式: int main( ) { … return 0; //the default return value is 0; }
  • 30. 注释C++的注释
  • 31. 基本的输出语句cout
  • 32. 练习程序hi.cc#include using namespace std; int main( ) { cout << "Hi Jian!" << endl; cout << "Have a nice day." << endl; return 0; }
  • 33. 练习程序myself.cc编写一个程序,打印出自己的: 姓名 性别 年龄 家庭住址 电话号码 爱好 每一条信息输出为一行
  • 34. 在hi.cc中使用字符串#include using namespace std; int main() { char name[ ] = "John"; cout << "Hi " << name << "!" << endl; cout << "Have a nice day." << endl; return 0; }
  • 35. 字符与字符串类型字符,字符串/字符数组 char ch = ‘A’; char str1[20] = "Hello world!"; char str2[ ] = "Have a nice day!";
  • 36. 不同的main()格式命令行参数 % ls –l (or ls -al ) % vi hello.cc 在程序中使用命令行参数 int main(int argc, char *argv[ ])
  • 37. 命令行参数程序cmdline.cc#include using namespace std; int main (int argc, char* argv[ ]) { for(int i=0; i38. 使用命令行参数的hi.cc使用命令行参数,重新编写练习程序 cmdline.cc % hi John % hi Lisa % hi "G. Bush"
  • 39. 基本输入语句cin语句 使用cin语句的hi.cc 重写hi.cc程序,不带命令行参数 程序自动提示用户输入字符串来获得姓名与年龄
  • 40. 练习程序age.cc#include using namespace std; int main() { unsigned int age; char name [50]; cout << "please enter your name:" << endl; cin >> name; cout << "please enter your age:" << endl; cin >> age; cout << "your name is:" << name << endl; cout << "You were " << age -2 << " years old two years ago. \n"; }
  • 41. 条件语句if语句 if…else语句 不同if的等价与不等价形式 … char ch; cin >> ch; if (ch == ‘y’) //note the difference: if ( ch = ‘y’) cout << "good" << endl; else cout << "try again." << endl; …
  • 42. 练习程序grade.ccThis is your assignment.
  • 43. Q & AThank You!
  • 44. The C++ Programming Language Chapter 2
  • 45. 字符集abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 0 1 2 3 4 5 6 7 8 9 _ + - * / % = . , : ? ’ \ " ~ | ! # & ( ) [ ] { } ^ < > 空白
  • 46. C++的保留字auto, bool, break, case, catch, char, class, const, const_cast , continue, default, delete, do, double, else, enum, extern, false, float, for, friend, goto, if, inline, int, long, new, operator, private, protected, public, return, short, signed, sizeof, static, struct, switch, template, this, throw, true, try, typedef, union, unsigned, virtual, void, while, …
  • 47. 常量与变量内存 程序的内存使用 常量 变量 动态内存 变量的类型
  • 48. C++变量名变量名(identifier) 第一个字符必须是字母或下划线 只能使用字母,数字,或下划线 中间不能有空格 不能是保留字,不能与全局函数和数据类型同名 C++严格区分大小写(UNIX中……) 使用易懂的变量名(一般是相关的英语单词或者缩写) 长度一般不要超过32个字符 不单是变量名,所有需要自己起名的地方都需要遵守这样的规则。
  • 49. C++变量C++是强类型语言 每一个变量都有确定的类型,且保持不变 基本数据类型 整型,int, 字符型, char, 实型, float, double, 逻辑型, bool ( standard c++ new feature ! )
  • 50. 基本数据类型1char, unsigned char, signed char, int, unsigned int, signed int, short int, unsigned short int, signed short int, long int, signed long int, unsigned long int, float, double, long double, bool void :enum,struct,union,array,pointer,class
  • 51. 基本数据类型2实型数据 (float, double…) 无unsigned.
  • 52. The standard C++ new featuresbool: 其值必为关键字true 或false 四个转型运算子: static_cast: compiling time to check data type(primitive). const_cast: only for constant data type converting. dynamic_cast: usually for top-down data type cast. reinterpret_cast: more general cast for all data types. (到多态的时候再详细讲)
  • 53. 变量与数据类型C++是强类型语言 先声明,后使用 C++编译器对变量声明的处理
  • 54. 一个使用变量的程序例子#include using namespace std; int main( ) { int i; i = 5; cout << "i = " << i << endl; i = 8; cout << "i = " << i << endl; return 0; }
  • 55. 另一个使用变量的例子程序#include using namespace std; int main( ) { i = 5; //see what happens… cout << "i = " << i << endl; i = 8; cout << "i = " << i << endl; return 0; int i; }
  • 56. 变量与变量的size变量都有类型 变量在内存中的大小 int i; double d; cout << "size of i is " << sizeof( i ) << endl; cout << "size of int is " << sizeof( int ) << endl; cout << "size of d is " << sizeof( d ) << endl; cout << "size of double is " << sizeof( double ) << endl;
  • 57. 程序size.cc编写一个程序,打印出所有C++基本类型的大小 #include using namespace std; int main() { cout << "size of char is: " << sizeof(char) << endl; cout << "size of unsigned char is: " << sizeof(unsigned char) << endl; cout << "size of signed char is: " << sizeof(signed char) << endl; cout << "size of int is: " << sizeof(int) << endl; cout << "size of unsigned int is: " << sizeof(unsigned int) << endl; cout << "size of signed int is: " << sizeof(signed int) << endl; cout << "size of short int is: " << sizeof(short int) << endl; …… }
  • 58. 变量的取值范围变量的类型与值的范围 常用类型的取值范围
  • 59. 常量常量与常量的数据类型 const double pi=3.14
  • 60. const限定符限定一个常量或者函数 方便编译器来检测非法的修改操作
  • 61. 运算符运算符 +,-,*,/,%,… ++,--, ==, >, <, >=, <=, != !, &&, || & | ^ ~ << >> 结合性 优先级: see table 3-1 in page 35 in the recommended book 1.
  • 62. 运算符的使用if ( demo = 2 ) 与 if (demo == 2 ) if ( 2== demo ) //左值与右值。 if ( demo != 2 ) 与 if ( demo =! 2 )
  • 63. 运算符的优先级int a=8,b=4,c=5; cout << (a%b ? b : c); cout << a%b ? b:c;
  • 64. 变量的赋值赋值表达式 变量的初始化 一次声明多个变量 声明并初始化变量
  • 65. 无符号类型的值无符号整数类型的回绕 unsigned short int snum; snum = 65535; cout << "snum=" << snum << endl; snum = snum + 1; cout << "snum=" << snum << endl;
  • 66. 有符号类型的值有符号整数类型的回绕 int inum = 2147483647; cout << "inum = " << inum << endl; inum = inum + 1; cout << "inum = " << inum << endl;
  • 67. 常用类型的取值范围常用类型的取值范围 int i = 65535; int j = 65535; cout << i*j/9 << endl;
  • 68. 练习为表示如下数据,应该使用什么类型的变量: 年龄 姓名 工资 电话号码 身份证号码 西三环到东三环的距离
  • 69. 练习程序bin.cc#include using namespace std; int main( ) { int a = 10; cout << "Please enter a number:" << endl; cin >> a; unsigned int r; int k; unsigned int j; char str[33]; memset(str, '0', 33); str[32]='\0'; r = a; int i = 32;
  • 70. 练习程序bin.ccdo { j = r; r = r/2; k = j - r * 2; if (k) str[--i] = '1'; else str[--i] = '0'; } while(r != 0); cout << str << endl; }
  • 71. 枚举类型enum color{RED, GREEN, BLUE, WHITE, BLACK}; color tvColor = GREEN; Enum constant variable does not need memory allocation. The default value in Enum is: 0, 1, 2, 3, 4…. Specify the element values: enum color {RED=100, GREEN=200, BLUE, WHITE=300, BLACK=400}
  • 72. 表达式左值与右值 float a; a = 5/2; ++a; 求值顺序 特殊表达式: ( ? : ) 逗号表达式: int a, b, c; a = 1, b=a=2, c=b+3;
  • 73. 表达式的求值顺序求值顺序 副作用
  • 74. 表达式的左值与右值int a, b, c,d; int e = (a = 1, b = a, c = a+b, d = c + 5); (a = 1, b = a, c = a+b, d = c + 5) = 8; e = (a = 0, b = a + 5, b+2); (a = 0, b = a + 5, b+2) = 9; //ohps …, you may get problem...
  • 75. 练习程序comma.cc#include using namespace std; int main( ) { int a, b, c,d; int e = (a = 1, b = a, c = a+b, d = c + 5); (a = 1, b = a, c = a+b, d = c + 5) = 8; cout <<"d=" << d << endl; }
  • 76. 程序语句控制语句 表达式语句 空语句 语句块
  • 77. 控制语句条件判断语句 if ( ) { … } if ( ) {…} else {…} 循环控制语句 while( ) { … } do { … } while( ); for ( ) { … } 多路选择语句 switch( ) { case: }
  • 78. 循环语句for语句 do…while语句 while语句 break语句 continue语句
  • 79. 分支语句switch语句 switch(ss) { case 1: … break; case 2: … break; default: break; };
  • 80. 循环语句程序例子 chengFa.cc编写一个程序,打印出乘法口诀表 分别使用for语句,do…while语句,while语句来实现The output is: 1x1=1 1x2=2, 2x2=4 1x3=3, 2x3=6, 3x3=9 1x4=4, 2x4=8, 3x4=12, 4x4=16 1x5=5, 2x5=10, 3x5=15, 4x5=20, 5x5=25 1x6=6, 2x6=12, 3x6=18, 4x6=24, 5x6=30, 6x6=36 1x7=7, 2x7=14, 3x7=21, 4x7=28, 5x7=35, 6x7=42, 7x7=49 1x8=8, 2x8=16, 3x8=24, 4x8=32, 5x8=40, 6x8=48, 7x8=56, 8x8=64 1x9=9, 2x9=18, 3x9=27, 4x9=36, 5x9=45, 6x9=54, 7x9=63, 8x9=72, 9x9=81
  • 81. 练习程序year.ccThis is your assignment. 判断输入的年份是否是闰年。
  • 82. Q & AThank You!
  • 83. The C++ Programming Language Chapter 3
  • 84. 函数什么是函数 函数的基本要素 参数 返回值 函数的声明与定义 形参与值参 函数的调用
  • 85. 定义函数<返回类型> 函数名( <参数表> …) { … return … } <参数表> <参数类型> <参数名称>
  • 86. 函数定义的例子#include using namespace std; void disp(char str[ ] ) { cout << "This is your string: " << str << endl; } int main( ) { char course1[ ] = "C++"; char course2[ ] = "Java"; char course3[ ] = "Oracle"; char course4[ ] = "UNIX"; disp( course1 ); disp( course2 ); }
  • 87. 函数声明<返回类型> 函数名( <参数表> …); void disp( char* ); float average(int, int); float average(int a, int b); 为什么需要函数声明?
  • 88. 调用函数函数的形参 函数的调用过程 填入值参 获得返回值
  • 89. 栈的技术简介栈的工作原理 函数的调用与栈
  • 90. 栈的原理i = f1( ); j = f2( ); cout << i << endl; cout << j << endl;cout << f1( ) << endl; cout << f2( ) << endl; #include using namespace std; int f1(); int f2(); int main( ) { int i, j; i = f1( ); j = f2( ); cout << i << endl; cout << j << endl } int f1( ) { int n = 5000; return n; } int f2( ) { int n; return n; }
  • 91. 变量的作用域局部变量与全局变量
  • 92. 默认参数函数的形参可以指定默认值 必须从右到左指定参数的默认值 函数在调用时,是按从左到右的顺序在匹配参数
  • 93. 使用默认参数的函数例子enum Sex{MALE, FEMALE}; void disp(char *name, Sex gender=MALE); 如果在函数声明中指定了默认值,则在函数定义时不能再指定
  • 94. 内联函数提高程序运行效率 内联函数的定义 inline int isnumber(char ch) { return ((ch>=‘0’ && ch<=‘9’) ? 1 : 0); } 必须先定义,不支持函数原形(声明) 不支持结构控制语句
  • 95. 递归函数一个函数调用它自己 如何正确的递归 必须有结束的条件 并且该条件一定能够满足
  • 96. 使用与不使用递归的例子程序编写一个程序bigsum.cc ,使用一个函数来求n的值: #include using namespace std; int bigsum(int a) { if(a == 0) return 0; return a + bigsum(a - 1); } int main() { int n; cout << "Please input a number: "; cin >> n; int m = bigsum(n); cout << "The sum is: " << m; cout << endl; }
  • 97. 练习程序nbang.cc使用递归函数,编写一个程序来求n!的值: This is your assignment…
  • 98. 函数的重载C++中的函数可以重载 什么是函数的重载: 对于在不同类型上作不同运算而又用同样的名字的情况,称为重载。 函数重载的注意事项: 重载函数至少在参数个数,参数类型, 或参数顺序上有所不同。
  • 99. 函数重载的例子求两个数的平均值 double Average(int, int); double Average(float, float); double Average(double, double); double Average(long, long);
  • 100. 思考题 在一个程序中定义了这两个函数会怎样? int Area(int width, int length=1); int Area(int size);
  • 101. Area.cc source code#include using namespace std; int Area(int width, int length = 1) { return width * length; } int Area(int size) // int Area(int size, int leng) is not allowed { return size * size; } int main( ) { cout << Area(3, 5) << endl; //set length = 5 instead. cout << Area(10) << endl; //is this ok? }
  • 102. 函数参数的const限定可以使用const限定词来修饰形参以保护实参不被修改。 const形参的意义 #include using namespace std; void disp(const int I) { cout << I << endl; I = 100; // think about this. } int main( ) { disp(50); }
  • 103. 程序的结构多文件结构 外部变量与内部变量 变量的作用域与可见性 头文件 静态全局变量 静态函数
  • 104. 多文件结构按不同的功能模块将程序的源代码划分在多个文件中 不同源文件之间可以共享变量声明与类型定义 C++多文件的划分原则
  • 105. 外部变量与内部变量存储类:auto, extern, register, static, volatile. 什么是外部变量 什么是内部变量
  • 106. 变量的作用域与可见性局部变量的作用域 静态局部变量的作用域 全局变量的作用域 外部变量的作用域 常量的作用域
  • 107. 头文件头文件的作用 如何组织头文件 头文件的使用 编译选项
  • 108. 静态全局变量何为静态全局变量 只在本源文件中可用
  • 109. 静态函数定义静态函数 只在本源文件中可用
  • 110. 改写bigsum.cc与nbang.cc程序将bigsum.cc与nbang.cc改写成多文件结构,每个文件只能有一个函数
  • 111. 改写bigsum.cc与nbang.cc程序分别将前面的函数改为静态函数,再次编译并运行所有的程序 This is your assignment…
  • 112. 练习程序hash.cc#include using namespace std; int main( ) { char line[100]; cout << "Please enter a string:" << endl; cin >> line; int ch = 0; for(int i=0; i
  • 113. 练习程序mywc.cc输入一行文字,统计单词的个数。 为了输入的时候能包含空格,程序使用了getline函数。 #include using namespace std; int main( ) { cout << "Please enter a line:" << endl; char line[120]; int cnt = 0; cin.getline(line, 120); int i = 0;
  • 114. 练习程序mywc.ccwhile (i
  • 115. Q & AThank You!
  • 116. The C++ Programming Language Chapter 4
  • 117. 复杂数据类型数组 结构 指针
  • 118. 数组1由若干个同类型变量组成的集合 数组的声明 <元素类型> 数组名[元素个数]; 下标是数组元素到开始的偏移量 数组下标从0开始 char buf[4];buf[0]buf[1]buf[2]buf[3]
  • 119. 数组2数组在声明时,元素个数必须是常量或常量表达式 char buf[10]; int I; char buf[I]; //??? int I = 10; char buf[I]; //??? const int i = 10; char buf[i]; char buf[i+1];
  • 120. 数组3如果数组的声明带有初始化,可以直接对整个数组赋值 访问数组元素,使用下标操作符[ ] int iA[10]; iA[0] = 0; iA[1] = 1; int I = 0; I = iA[0] + iA[1];
  • 121. 数组的初始化在声明的时候就初始化 int iA[5] = {0,1,2,3,4}; int iB[ ] = {1,2,3}; 使用赋值语句初始化数组 iA[0] = 0; iA[1] = 1; 数组的边界问题 int iC[5]; iC[10] = 100; //run time ??? Question: does C++ compiler have array bound checking?
  • 122. 数组程序例子编写一个程序,从键盘接受一个字符串,将该字符串颠倒顺序,然后打印出来…
  • 123. 练习程序findmax.cc#include using namespace std; int main( ) { int iA[ ] = {103, 5, 68, 115, 32, 23, 66, 599, 38, 444}; for(int i = 0; i < 10; i++) { for(int j = 0; j < i; j++) { int temp; if(iA[i] < iA[j]) //if(iA[i] < iA[j]) { temp = iA[i]; iA[i] = iA[j]; iA[j] = temp; } } } cout << "The bigNumber is: " << iA[9] << endl; }
  • 124. 多维数组二维数组与多维数组: int iA[5][10]; int iB[2][3] = { {1,2,3}, {4,5,6}}; int iC[2][4][6]; 多维数组的初始化 仅有第一个维数可以省去 int iB[ ][3] = { {1,2,3}, {4,5,6}, {7,8,9}};
  • 125. 数组练习程序mdim.cc#include using namespace std; int maximum(int [][4], int, int); int main ( ) { int sg[3][4] = { {68,77,73,86}, {87,96,78,89}, {90, 70, 81, 86}}; cout << "the max grade is " << maximum(sg, 3,4) << endl; }int maximum(int grade[ ][4], int row, int col) { int max = grade[0][0]; for (int i=0; i < row; i ++) for (int j=0; j< col; j++) if(grade[i][j] > max) max = grade[i][j]; return max; }
  • 126. 结构1将不同类型的相关数据信息组织在一起 是用户自定义的类型 需要先声明类型的定义才能使用 结构与数组的区别 数组只是同一个数据类型的聚集 数组本身不是一个新的数据类型
  • 127. 结构2struct <结构名> { <成员类型> <成员变量名>; <成员类型> <成员变量名>; <成员类型> <成员变量名>; … } (结构变量名); struct Person { char name[20]; unsigned long id; float salary; char address[200]; } p1, p2;
  • 128. 结构的赋值1通过取成员操作(.)来引用结构变量的元素 Person p1 = { "G.W Bush", 1000010, 1.5 , "ZhongGuanChun, Beijing, China"}; strcpy(p1.name, "G.W Bush"); p1.id = 1000010; p1.salary = 1.5; strcpy(p1.address, "ZhongGuanChun, Beijing, China");
  • 129. 结构的赋值2结构赋值的例子 Person p1 = { "G. W Bush", 1000010, 1.5 , "ZhongGuanChun, Beijing, China"}; Person p2 = p1;
  • 130. 结构的存储模式1每一个成员都有自己的存储空间 对每一个成员的操作都是独立的,各元素间不会相互影响nameidsalary
  • 131. 结构的存储模式2#include using namespace std; struct Person { char name[20]; unsigned long id; float salary; }; int main( ) { Person p1 = {"Zhang Weilong", 1000101, 32}; cout << "&p1=" << &p1 << endl; cout << "&p1.name=" << &p1.name << endl; cout << "&p1.id=" << &p1.id << endl; cout << "&p1.salary=" << &p1.salary << endl; }
  • 132. What are pointers for ?Accessing array elements. Passing arguments to a function when the function needs to modify the original argument. Passing arrays and strings to functions. Obtaining memory from the system. Creating data structures such as linked lists.
  • 133. Pointer, address, variableint theVariable =5; int * pPointer = & theVariable;5200020002001200220032004200520062007200820092010addresstheVariablepPointer
  • 134. 指针1编译器为变量与常量分配存储空间 任何存储空间都用地址来表示 任何变量/常量都有地址 一个变量的地址也是一个有意义的值 变量地址也可进行运算 这个值也可以用另一个变量来存储 这"另一个"变量的类型就是指针类型
  • 135. 指针2指针就是用来存储其他变量的地址的变量 指针变量自己也有地址 指针是有类型的 指针的类型要跟它所指向的变量的类型一致 整数指针,浮点数指针
  • 136. 理解指针的例子程序addr.cc定义下面的变量,分别输出它们的值与他们的存储地址 int iVal1 = 1; int iVal2 = 2; double dVal1 = 1.1; double dVal2 = 2.2;
  • 137. 指针的定义<数据类型> *<指针变量名>; int* ip; const int * icp; char * str; NULL指针
  • 138. 指针的操作取地址操作符 & int * ip; int i = 89; ip = & i; 引用指针指向的变量 * 获得该指针所指向的变量 int j = 0; j = *ip; cout << j;
  • 139. 指针的类型整数型变量 int iVal; iVal = 10; 整数指针性变量 int *iPtr; iPtr = & iVal; 整数指针变量的地址 int **ipp = & iPtr; Any data type in c++ can be a pointer type.
  • 140. 指针的使用指针在使用前必须初始化 指针的类型决定了指针所参与的运算 指针只能进行加减法运算
  • 141. 理解指针的例子程序 ptracc.cc#include using namespace std; int main( ) { int var1 = 11; int var2 = 22; int * ptr; ptr = &var1; cout << * ptr << endl; ptr = & var2; cout << * ptr << endl; }
  • 142. 理解指针的例子程序 ptracc.ccVar1 (11)Var2 (22)Var1 (11)Var2 (22)* ptr is 11 * ptr is 22 ptr ptr
  • 143. 指针与数组数组的本质就是数组里所有变量的首地址 数组的下标操作就是针对地址
  • 144. 指针与数组的例子程序 ptr.cc分别用数组的方式与指针的方式来操作 int iv[5] 分别给他们赋初值并输出他们的值与地址: #include using namespace std; int j; int iv[5] = {1,2,3,4,5}; int main() { int a = 800; int i; int b = 900; int *ptr = &i; i = 500; cout << "*ptr=" << *ptr << endl; cout << "ptr=" << ptr << endl; cout << "i=" << i << endl;
  • 145. 指针与数组的例子程序 ptr.cccout << "&i=" << &i << endl; ptr ++; cout << "ptr=" << ptr << endl; cout << "*ptr=" << *ptr << endl; ptr = iv; cout << "ptr=" << ptr << endl; for(int i=0; i<5; i++) cout << *(ptr+i) << ", "; cout << endl; for(int i=0; i<5; i++) cout << iv[i] << ", "; cout << endl; for(int i=0; i<5; i++) cout << *(iv+i) << ", "; cout << endl; for(int i=0; i<5; i++) cout << ptr[i] << ", "; cout << endl; }
  • 146. 结构指针结构是一种数据类型 结构类型也有指针 结构变量vs结构指针变量 结构指针变量的操作 结构变量用( . )操作来存取成员 结构的指针用( -> )操作来存取成员
  • 147. 结构数组数组的元素是某一个结构类型 struct Person { char name[20]; unsigned long id; float salary; char address[200]; }; Person allPeople[100];
  • 148. 结构中的数组元素结构中的某个元素是数组类型 struct Person { char name[20]; unsigned long id; float salary; char address[200]; }; Person Jack = {"Jack", 2L, 8000.00, "Toronto"};
  • 149. 指针作形参利用指针在函数中传递参数
  • 150. 程序swap1.cc#include using namespace std; void swap(int, int); int main( ) { int a = 3, b = 8; cout << "a= " << a << ", b = " << b << endl; swap(a,b); cout << "after swapping… \n"; cout << "a = " << a << ", b = " << b << endl; } void swap(int x, int y) { int temp = x; x = y; y = temp; }
  • 151. 程序swap2.cc#include using namespace std; void swap(int *, int * ); int main( ) { int a = 3, b = 8; cout << "a= " << a << ", b = " << b << endl; swap(&a, &b); cout << "after swapping… \n"; cout << "a = " << a << ", b = " << b << endl; } void swap(int * x, int * y) { int temp = * x; * x = * y; * y = temp; }
  • 152. 练习程序date.ccThis is your assignment… 要求用结构、指针。
  • 153. Q & AThank You!
  • 154. The C++ Programming Language Chapter 5
  • 155. 内存管理与引用C++的内存管理 引用
  • 156. 使用动态内存内存的申请与释放
  • 157. 堆与内存管理堆空间简介 堆空间的管理 new/delete
  • 158. New操作int * ip; ip = new int; float *fp; fp = new float; int *ipA = new int[5]; int * pA[5]; for(int j=0; j<5; j++) pA[j] = new int[10];
  • 159. Delete操作delete ip; delete fp; delete [ ] ipA; for(int j=0; j<5; j++) delete [ ] pA[j];
  • 160. 含指针的结构变量的赋值如果结构中含有指针成员,使用了动态空间
  • 161. 通过指针传递参数函数的形参类型可以是指针 通过指针来传递参数
  • 162. 练习程序ptrsort.cc#include using namespace std; int main( ) { void bsort(int*, int); const int N =10; int data[N]= {37,84,62,91,11,65,57,28,19,49}; int *arr = new int[N]; for( int i=0; i
  • 163. 练习程序ptrsort.ccvoid bsort(int* ptr, int n) { void order(int *, int *); int j,k; for(int j=0; j * numb2) { int temp = * numb1; *numb1 = * numb2; *numb2 = temp; } }
  • 164. 危险的指针用法使用NULL指针的内容 使用没有初始化的指针变量 使用已经被delete 的指针内容 函数返回局部变量的地址 由函数申请的堆空间,而由调用者来释放
  • 165. 函数指针调用一个函数 函数都有地址,存放在内存的代码区(code). 函数指针 函数指针指向代码区中的某个函数。 函数指针的声明 int (*func) (char a, char b); int * func (char a, char b); //how about this one?
  • 166. 函数指针func is a pointer that points to a function. Example: int fn1 (char a, char b); int* fn2(char x, char y); int fn3(int a); int (* fp1) (char a, char b); int ( * fp2) (int s); fp1 = fn1; //ok fp1 = fn2; //error fp2 = fn3; // ok fp2 = fp1; //error fp1 = fn2(‘a’, ‘b’); //error. fp1(‘a’, ‘b’); //ok
  • 167. 函数指针 funcptr.cc#include using namespace std; int swap(int *a, int *b) { int t; t = *a; *a = *b; *b = t; } int main() { int i = 100; int j = 200; int m = 300; int n = 400; cout << "i= " << i << endl;
  • 168. 函数指针 funcptr.cc cout << "j= " << j << endl; swap(&i, &j); cout << "(Swap)i= " << i << endl; cout << "(Swap)j= " << j << endl; int (*func)(int *, int *); func = swap; func(&m, &n); cout << "(Func)m= " << m << endl; cout << "(Func)n= " << n << endl; } //end of funcptr.cc
  • 169. 指针的指针可以存在多层的指针 int iNum; int *ptr; int **pptr;
  • 170. void指针void * ptr;
  • 171. const与指针普通指针:指向的对象的值可以改变,指针的值也可改变 int *p; 常量指针:指针可以指向不同的对象,但其指向的对象的值不能变 const int *p; 指针常量:指针本身是常量,只能指向固定的对象,但其指向的对象的值可改变 int * const p; 必须初始化 常量指针指向常量 const int * const p; 必须初始化
  • 172. 引用引用是一个变量的别名 引用的声明 int iVal; int & iRef = iVal; 引用的使用 声明的时候就必须初始化 引用不能重新赋值(不能重新绑定为另一个新对象的别名)
  • 173. 引用的例子程序 myRef.cc#include using namespace std; int main() { int iVal = 100; cout << "iVal=" << iVal << endl; cout << "&iVal=" << &iVal << endl; int &iRef = iVal; cout << "iRef = " << iRef << endl; cout << "&iRef = " << &iRef << endl; iRef = 200; cout << "iVal=" << iVal << endl; cout << "iRef = " << iRef << endl; }
  • 174. 引用的重新赋值 myRef2.cc为引用重新赋值 int iA; int &iRef = iA; iRef = 5; cout << "iA=" << iA << "; &iA = " << &iA << endl; cout << "iRef=" << iRef << "; &iRef = " << &iRef << endl; int iB = 9; iRef = iB; cout << "iA=" << iA << "; &iA = " << &iA << endl; cout << "iRef=" << iRef << "; &iRef = " << &iRef << endl; cout << "iB=" << iB << "; &iB = " << &iB << endl;
  • 175. 通过引用来传递参数函数的形参可以是引用 通过引用来传递参数
  • 176. 引用作为函数的参数 ref1.cc#include using namespace std; void disp(int &i) { cout << "i=" << i << "; &i=" << &i << endl; } int main() { int a = 100, b = 200; cout << "a=" << a << "; &a=" << &a << endl; disp(a); cout << "b=" << b << "; &b=" << &b << endl; disp(b); }
  • 177. 使用引用的swap.cc程序#include using namespace std; void swap(int &, int & ); int main( ) { int a = 3, b = 8; cout << "a= " << a << ", b = " << b << endl; swap(a, b); cout << "after swapping… \n"; cout << "a = " << a << ", b = " << b << endl; } void swap(int & x, int & y) { int temp = x; x = y; y = temp; }
  • 178. 函数返回一个类型的引用函数可以返回任何类型的引用 如果返回的引用对应于一个局部变量?
  • 179. 函数返回引用 ref3.cc指出下列程序的输出结果分别是什么#include using namespace std; int & getInt(const int v) { int t = v; return t; } int main() { int n = getInt(888); int m = getInt(999); cout << "n=" << n << endl; cout << "m =" << m << endl; }
  • 180. 堆中指针变量的引用 testDelete.cc看看下列程序有无问题 #include using namespace std; int & getInt(const int v) { int *p = new int(v); return *p; } int main() { int &n = getInt(888); cout << n << endl; int *pp = &n; delete pp; }如何释放堆中的空间?int* p = & n; delete p;
  • 181. 引用的使用尽量使用引用来传递参数 尽量使用const来保护引用 尽量使用引用来代替指针 危险的引用方法 返回一个局部变量的引用
  • 182. Q & AThank You!
  • 183. The C++ Programming Language Chapter 6
  • 184. 面向对象的C++编程类 构造函数与析构函数 类成员的屏蔽与作用域 面向对象的程序设计方法
  • 185. 新的类型类 一个类似于结构的类型 类的声明 class 类名 { <成员定义>; … };
  • 186. 结构的定义struct Person { char name[30]; unsigned int age; char address[100]; float salary; };
  • 187. 结构的操作1void setName(Person *pP, char* str) { strcpy(pP->name, str); } void setAge(Person *pP, unsigned int yr) { pP->age = yr; } void setSalary(Person *pP, float s) { pP->salary = s; } void setAddress(Person *pP, char* addr) { strcpy(pP->address, addr); }
  • 188. 结构的操作2void disp(Person *pP ) { cout << "Name:" << pP->name << endl; cout << "Age:" << pP-> age << endl; cout << "Address:" << pP-> address << endl; cout << "Salary:" << pP->salary << endl; }
  • 189. 使用结构变量的person.cc#include … int main( ) { Person Jack = { "Jack", 30, "Beijing China", 8000.0}; disp( &Jack ); Person somebody; setName( &somebody, "Lisa"); setAge( &somebody, 20); setAddress( &somebody, "Toronto, Canada"); setSalary( &somebody, 6000.0); disp( &somebody ); }
  • 190. 封装好的结构1struct Person { char name[30]; unsigned int age; char address[100]; float salary; void setName(char*); void setAge(unsigned int); void setAddress(char*); void setSalary(float); void disp( ); };
  • 191. 封装好的结构2void Person::setName(char* str) { strcpy(name, str); } void Person::setAge(unsigned int yr) { age = yr; } void Person::setSalary(float s) { salary = s; } void Person::setAddress(char* addr) { strcpy(address, addr); }
  • 192. 封装好的结构3void Person::disp( ) { cout << "Name:" << name << endl; cout << "Age:" << age << endl; cout << "Address:" << address << endl; cout << "Salary:" << salary << endl; }
  • 193. 使用封装后的结构变量的person.cc#include … int main( ) { Person Jack = { "Jack", 30, "Beijing China", 8000.0}; Jack.disp( ); Person somebody; somebody.setName( "Lisa" ); somebody.setAge( 20 ); somebody.setAddress( "Toronto, Canada" ); somebody.setSalary(6000.0); somebody.disp( ); }
  • 194. 仍然存在的问题#include … int main( ) { Person Jack = { "Jack", 30, "Beijing China", 8000.0}; Jack.disp( ); Jack.salary = 1000.00; Jack.disp( ); }
  • 195. 如何实现数据隐藏引入class类型 对数据成员进行保护 增加存取范围 私有成员private 保护成员protected 公共成员public
  • 196. 定义类来实现数据隐藏class Person { private: char name[30]; unsigned int age; char address[100]; float salary; public: void setName(char* str); void setAge(unsigned int yr); void setAddress(char *str); void setSalary(float yuan); void disp( ); };
  • 197. 类成员的作用域属性在C++中,class与struct的区别 struct的缺省作用域为public class的缺省作用域为private private的数据成员 只能被类的成员函数所使用
  • 198. 使用对象的person.cc#include … int main( ) { Person somebody; somebody.setName( "Lisa" ); somebody.setAge( 20 ); somebody.setAddress( "Toronto, Canada" ); somebody.setSalary(6000.0); somebody.disp( ); }
  • 199. 类的声明与类的定义类的声明 一般在头文件中 声明类的所有成员 声明类的成员的属性 声明所有接口(公共函数成员)的签名(格式) 类的定义 一般放在程序文件( .cc文件)中 定义类的所有成员函数的具体实现方法
  • 200. 对象对象是类的一个实例 Person是一个class,它是一个数据类型 somebody是一个对象,它是一个具体的变量 类是一类对象的描述 定义结构,可以声明许多变量 定义类,可以声明许多对象
  • 201. 增加对象初始化自己的能力新person.cc程序的问题 Person Jack = { "Jack", 30, "Beijing China", 8000.0}; Jack.disp( ); 构造函数 一种特殊的函数 没有返回类型 只能作为是公共成员 只能用一个固定的名字,函数名就是类的名字
  • 202. Person类的构造函数class Person { … public: Person(char*, unsigned int, char*, float); };
  • 203. 构造函数的特点构造函数只在建立对象的时候自动被调用一次 构造函数必须是公共的,否则无法生成对象 构造函数只负责为自己的类构造对象
  • 204. 在构造函数中初始化变量Person::Person( ) : name("Jack"), age(30) { … }
  • 205. 有构造函数的例子 simpleClass.cc#include using namespace std; class A { int a; public: A( ) { cout << "A( )" << endl;} A(const int & o) //constructor overload { a = o; cout << "A(const int &)" << endl; } }; int main( ) { A o = A( ); int a=100; A p(a); }
  • 206. 析构函数与构造函数相对应 与构造函数的作用相反 析构函数的形式 ~类名( ) { … }
  • 207. 析构函数的特点固定的函数名称 ~类名( ) 没有返回类型 没有参数 不可以重载 一般由系统自动的调用
  • 208. C++默认的构造函数C++自动给每一个class加上一个构造函数 这个构造函数没有任何参数 这个构造函数也不做任何操作 如果用户自己定义了一个构造函数,C++就不再提供默认的构造函数了
  • 209. C++默认的析构函数C++自动给每一个class加上一个析构函数 析构函数不能有任何参数 这个析构函数也不做任何操作 如果用户自己定义了一个析构函数,C++就不再提供默认的析构函数了
  • 210. 构造函数的作用提供内部成员变量的初始化功能 完成对象的初始化 内存管理 实现对象的拷贝功能
  • 211. 构造函数的调用class A { public: void disp( ); }; A a, *b = new A, *c = new A( ), *d = new (A); //are they all right? a = A( ); A aa( ); //won’t instantiate any object.
  • 212. 构造对象的顺序局部与静态局部对象,以声明的顺序构造 静态对象只被构造一次 全局对象在main之前构造 全局对象的构造无特殊顺序 数据成员对象,以声明顺序构造
  • 213. 析构函数的作用与构造函数相反 释放资源 内存管理 析构函数的调用 什么时候析构函数被调用
  • 214. 析构函数的例子#include using namespace std; class Str{ int len; char *string; public: Str(char* = "default"); ~Str( ); }; Str::Str(char *s) { string = new char[len=strlen(s)+1]; strcpy(string, s); }Str::~Str() { cout << "Destructor of " << string << endl; delete []string; } int main( ) { Str *words = new Str[3]; delete []words; }
  • 215. 析构函数的直接调用析构函数可以被直接调用 #include … int main( ) { … Person p; p.~Person( ); … }
  • 216. 对象指针定义的类就是一个数据类型 对象与对象指针 new 与 delete 对象指针的使用
  • 217. This成员this this的使用
  • 218. 对象的引用对象也可以有别名
  • 219. Person对象的指针与引用…… person::person(const person& p) { strcpy(this->name, p.name); this->age = p.age; strcpy(this->address, p.address); this->gender = p.gender; } ……
  • 220. 面向对象的程序设计方法1自然界就是由许多的对象组成 自然界中的任何一个实体都可以看作一个对象 非实体也能看成某种对象(逻辑上的实体) 自然界的现象就是许许多多的同类与不同类的对象在相互作用 一个对象包含一个或多个其他的对象 一个对象使用另一个或多个对象 同种或不同种的对象之间存在各种复杂的关系
  • 221. 面向对象的程序设计方法2分析并分解出某个问题中的种种对象 准确的描述所有对象之间的种种关系 找到它们之间的所有相互作用 用程序设计语言与工具来描述它们 用程序开发语言来表达(实现)它们
  • 222. 对象的特点对所有对象进行抽象总结 名称 属性 行为 用class来表述
  • 223. 传统的程序设计方法程序=数据+算法 算法=函数+控制流程 传统方法的特点 结构化封装,但无法隐藏 算法依赖于数据,更改与维护困难 重用性差
  • 224. 面向对象的方法分析问题,找到对象 抽象出对象的属性与特点 划分出类 确定类与类的关系 用类来定义程序结构
  • 225. 面向对象的优点1更好的封装 数据隐藏 操作屏蔽 把特定的数据与相应的操作组合在一起 把可见的与不可见的部分很理想的分离开来 C++语言中封装是由类来实现的
  • 226. 面向对象的优点2继承 更好的可重用特性 软件更易扩展与更可维护性
  • 227. 面向对象的优点3多态 最重要的面向对象特性之一 突出的优点
  • 228. Exercises设计一个叫做String的类,要求该类能够完成以下功能: (1) 构造函数能够根据实际传入的参数分配实际存储空间;缺省时为100字节; (2) 析构函数释放该空间; (3) 编写成员函数Assign,可以将一个字符串赋值给该类; (4) 编写成员函数Disp,可以将该类的内容打印到屏幕上; (5) 编写成员函数Replace,用于替换某一指定的字符串; (6) 编写成员函数Append,用于向已有的数据后面添加数据; (7) 编写成员函数Size,用于得到当前数据的真实长度。 编写测试程序,测试这个类。class String{ char * str; unsigned int len; public: String(); String(const char* sz); ~String(); //Return 0 -- success, -1 Error int Assign(char *); void Disp(); //Return 0 -- success, -1 Error int Replace(char* from, char* to); //Return 0 -- success, -1 Error int Append(char*); unsigned int Size(); };
  • 229. Q & AThank You!
  • 230. The C++ Programming Language Chapter 7
  • 231. 继承和多态什么是继承 继承与派生 继承的工作方式 私有成员与保护成员 构造函数与析构函数 虚函数与多态 多重继承与虚继承 抽象数据类型
  • 232. 什么是继承自动获得另一种事物的部分或者全部的东西(属性,能力) The "is a" relationship 是一种从属的关系 自然界中的"is a"关系非常普遍 C++使用继承来表示这种关系
  • 233. 继承与组合组合的概念 The "has a" relationship 是一种包含关系
  • 234. 继承与组合personstudentteacherPart time studentFull time studentstudent "is a" kind of person. Full time student "is a" kind of student ……. ComputerCPUMonitor… …Computer "has a" CPU Computer "has a" Monitor…
  • 235. 继承的描述继承是一种关系 反映了对象与对象之间的联系 由类与后继类来描述 前者也称基类 后继类也称派生类 从后者的角度看称为继承 从前者的角度看称为派生
  • 236. 继承的作用C++中,继承可以让一个类自动地获得另一个类的部分或全部的属性与操作 继承提高了代码的可重用性
  • 237. 继承的语法class 派生类名 : 基类名 { <派生类的成员>; <派生类的成员>; … };
  • 238. 继承的例子class Person { … public: void disp( ); }; class Student : public Person { public: int grade; void setGrade(int); };
  • 239. 哪些东西可以继承类成员的可见性 public private protected 派生方式影响可见性 class 派生类名 : 父类名
  • 240. 覆盖覆盖将隐藏基类的方法 class Student : public Person { public: int grade; void setGrade(int); void disp( ); }; void Student::disp( ) { cout << "disp() of Student." << endl; } 调用基类的方法 Person::disp( );
  • 241. 基类的内存模式enum Sex{MALE, FEMALE}; class Person { private: char name[20]; unsigned int age; protected: Sex gender; float salary; public: void Eat( ); void Drink( ); void Sleep( ); void Disp( ); };nameagegenderEatDrinkSleepsalaryDisp
  • 242. gradeStudydisp派生类的内存模式1class Student : public Person { private: int grade; public: void Study( ); void disp( ); };nameagegenderEatDrinkSleepsalarydisp
  • 243. 派生类的内存模式2在一个Student对象中,包含有一个Person对象 那么,在Student对象中,有没有Person对象的私有数据成员存在? unsigned int age float salary
  • 244. 类继承的程序例子 mamal.cc#include enum BREED { GOLDEN, CAIRN, DANDIE, SHETLAND, DOBERMAN, LAB }; class Mammal { public: // constructors Mammal(); ~Mammal(); //accessors int GetAge() const; void SetAge(int); int GetWeight() const; void SetWeight(); //Other methods void Speak() const; void Sleep() const; protected: int itsAge; int itsWeight; };
  • 245. 类继承的程序例子 mamal.ccclass Dog : public Mammal { public: // Constructors Dog(); ~Dog(); // Accessors BREED GetBreed() const; void SetBreed(BREED); // Other methods void WagTail(); void BegForFood(); protected: BREED itsBreed; };
  • 246. 构造函数构造函数的调用顺序 由基类到派生类 如何向基类的构造函数传递参数 容易犯的错 匹配构造函数
  • 247. 析构函数析构函数的调用顺序 由派生类到基类 直接调用派生类的析构函数 基类的析构函数是否也被调用?
  • 248. 哪些东西可以派生任何一个类都可能派生出新的类 原始数据类型无法派生 class A : public int { … };
  • 249. Polymorphism多态的本质 C++允许把派生类对象赋给基类的指针 所有的派生类在本质上都"is a"基类 用基类的指针调用任何方法,C++都能找到相应的派生类的方法
  • 250. Polymorphism example: horse.cc#include using namespace std; class Horse { public: void Gallop(){ cout << "Galloping...\n"; } virtual void Fly() { cout << "Horses can't fly.\n" ; } private: int itsAge; }; class Pegasus : public Horse { public: virtual void Fly() {cout<<"I can fly! I can fly! I can fly!\n";} }; const int NumberHorses = 5;
  • 251. Polymorphism example: horse.ccint main() { Horse* Ranch[NumberHorses]; Horse* pHorse; int choice,i; for (i=0; i> choice; if (choice == 2) pHorse = new Pegasus; else pHorse = new Horse; Ranch[i] = pHorse; } cout << "\n"; for (i=0; iFly(); delete Ranch[i]; } return 0; }
  • 252. 对象指针的转换Up casting Down casting
  • 253. 对象指针的转换 dyHorse.cc#include using namespace std; //enum TYPE { HORSE, PEGASUS }; class Horse { public: virtual void Gallop(){ cout << "Galloping...\n"; } private: int itsAge; }; class Pegasus : public Horse { public: virtual void Fly() {cout<<"I can fly! I can fly! I can fly!\n";} }; const int NumberHorses = 5;
  • 254. 对象指针的转换 dyHorse.ccint main() { Horse* Ranch[NumberHorses]; Horse* pHorse; int choice,i; for (i=0; i> choice; if (choice == 2) pHorse = new Pegasus; else pHorse = new Horse; Ranch[i] = pHorse; } cout << "\n";
  • 255. 对象指针的转换 dyHorse.cc for (i=0; i (Ranch[i]); //down cast if (pPeg) pPeg->Fly(); else cout << "Just a horse\n"; delete Ranch[i]; } return 0; }
  • 256. 虚函数1什么是虚函数 为什么要使用需函数
  • 257. 虚函数2虚函数的声明与定义 virtual void disp( ); 虚函数的工作原理 V table
  • 258. 虚函数的使用构造函数不能是虚函数 如果类中有任何一个成员函数是虚函数,那么析构函数应为虚函数 如果一个类肯定被用作其他派生类的基类,尽可能使用虚函数
  • 259. 虚函数使用 example vdog.cc#include using std::cout; class Mammal { public: Mammal():itsAge(1) { cout << "Mammal constructor...\n"; } virtual ~Mammal() { cout << "Mammal destructor...\n"; } void Move() const { cout << "Mammal move one step\n"; } virtual void Speak() const { cout << "Mammal speak!\n"; } protected: int itsAge; }; class Dog : public Mammal { public: Dog() { cout << "Dog Constructor...\n"; } virtual ~Dog() { cout << "Dog destructor...\n"; } void WagTail() { cout << "Wagging Tail...\n"; } void Speak()const { cout << "Woof!\n"; } void Move()const { cout << "Dog moves 5 steps...\n"; } };
  • 260. 虚函数使用 example vdog.cc int main() { Mammal *pDog = new Dog; pDog->Move(); pDog->Speak(); delete pDog; return 0; }
  • 261. 多重继承C++支持从多个基类中派生出一个新的类 多重继承的对象的构造顺序 多重继承同名时的歧义解析
  • 262. 多重继承的例子HorseBirdPegasus
  • 263. 多重继承的例子 mHorse.cc#include using std::cout; using std::cin; class Horse { public: Horse() { cout << "Horse constructor... "; } virtual ~Horse() { cout << "Horse destructor... "; } virtual void Whinny() const { cout << "Whinny!... "; } private: int itsAge; }; class Bird { public: Bird() { cout << "Bird constructor... "; } virtual ~Bird() { cout << "Bird destructor... "; } virtual void Chirp() const { cout << "Chirp... "; } virtual void Fly() const { cout << "I can fly! I can fly! I can fly! "; } private: int itsWeight; };
  • 264. 多重继承的例子 mHorse.ccclass Pegasus : public Horse, public Bird { public: void Chirp() const { Whinny(); } Pegasus() { cout << "Pegasus constructor... "; } ~Pegasus() { cout << "Pegasus destructor... "; } }; const int MagicNumber = 2; int main() { Horse* Ranch[MagicNumber]; Bird* Aviary[MagicNumber]; Horse * pHorse; Bird * pBird; int choice,i; for (i=0; i> choice; if (choice == 2) pHorse = new Pegasus; else pHorse = new Horse; Ranch[i] = pHorse; } cout << "\n"; for (i=0; iWhinny(); delete Ranch[i]; }
  • 265. 多重继承的例子 mHorse.cc for (i=0; i> choice; if (choice == 2) pBird = new Pegasus; else pBird = new Bird; Aviary[i] = pBird; } for (i=0; iChirp(); Aviary[i]->Fly(); delete Aviary[i]; } return 0; }
  • 266. 多重继承的麻烦horsebirdpegasusanimalpPeg -> GetAge() ?
  • 267. 虚继承pegasushorsebirdanimalvirtualvirtual
  • 268. 虚继承的例子 vHorse.cc#include using namespace std; typedef int HANDS; enum COLOR { Red, Green, Blue, Yellow, White, Black, Brown } ; class Animal // common base to both horse and bird { public: Animal(int); virtual ~Animal() { cout << "Animal destructor...\n"; } virtual int GetAge() const { return itsAge; } virtual void SetAge(int age) { itsAge = age; } private: int itsAge; }; Animal::Animal(int age): itsAge(age) { cout << "Animal constructor...\n"; }
  • 269. 虚继承的例子 vHorse.ccclass Horse : virtual public Animal { public: Horse(COLOR color, HANDS height, int age); virtual ~Horse() { cout << "Horse destructor...\n"; } virtual void Whinny()const { cout << "Whinny!... "; } virtual HANDS GetHeight() const { return itsHeight; } virtual COLOR GetColor() const { return itsColor; } protected: HANDS itsHeight; COLOR itsColor; }; Horse::Horse(COLOR color, HANDS height, int age): Animal(age), itsColor(color),itsHeight(height) { cout << "Horse constructor...\n"; }
  • 270. 虚继承的例子 vHorse.ccclass Bird : virtual public Animal { public: Bird(COLOR color, bool migrates, int age); virtual ~Bird() {cout << "Bird destructor...\n"; } virtual void Chirp()const { cout << "Chirp... "; } virtual void Fly()const { cout << "I can fly! I can fly! I can fly! "; } virtual COLOR GetColor()const { return itsColor; } virtual bool GetMigration() const { return itsMigration; } protected: COLOR itsColor; bool itsMigration; }; Bird::Bird(COLOR color, bool migrates, int age): Animal(age), itsColor(color), itsMigration(migrates){cout << "Bird constructor...\n";}
  • 271. 虚继承的例子 vHorse.cc class Pegasus : public Horse, public Bird { public: void Chirp()const { Whinny(); } Pegasus(COLOR, HANDS, bool, long, int); virtual ~Pegasus() {cout << "Pegasus destructor...\n";} virtual long GetNumberBelievers() const { return itsNumberBelievers; } virtual COLOR GetColor()const { return Horse::itsColor; } private: long itsNumberBelievers; };
  • 272. 虚继承的例子 vHorse.ccPegasus::Pegasus( COLOR aColor, HANDS height, bool migrates, long NumBelieve, int age): Horse(aColor, height,age), Bird(aColor, migrates,age), Animal(age*2), itsNumberBelievers(NumBelieve) { cout << "Pegasus constructor...\n"; }
  • 273. 虚继承的例子 vHorse.cc int main() { Pegasus *pPeg = new Pegasus(Red, 5, true, 10, 2); int age = pPeg->GetAge(); cout << "This pegasus is " << age << " years old.\n"; delete pPeg; return 0; }
  • 274. 抽象数据类型C++支持抽象数据类型 任何一个抽象类都是ADT ADT的使用 从抽象类派生新的类 (ADT can’t instantiate object directly) 确保实现所有的纯虚函数 ( virtual void Draw() = 0; )
  • 275. Exercises编写一个存储艺术作品的程序。艺术作品分为三类:Painting、Music和Chamber,Chamber是Music中的一类。要求如下所述。 ①每件作品都要标明著者、作品标题、作品诞生年份及其所属分类。 ② Painting类要求显示画的宽和高等尺寸信息。 ③ Music类要求显示能够代表其内容的关键信息,例如"D Major"。 ④ Chamber类要求显示其中包括的演奏人员的数目。 编写测试程序测试设计一个程序,有一个汽车类vehicle,它具有一个需要传递参数的构造函数,类中的数据成员包括:车轮个数wheels和车重weight作为保护成员:小车类car是它的派生类,其中包含载人数passengers;卡车类truck是vehicle的派生类,其中包含载人数passengers和载重量payload。每个类都有相关数据的输出方法。 编写测试程序测试
  • 276. Q & AThank You!
  • 277. The C++ Programming Language Chapter 8
  • 278. More about class in C++友员 静态成员 成员函数的重载 拷贝构造函数 运算符 类型转换操作符 重载new与delete 流操作符
  • 279. Static Members什么是静态成员 static修饰符 静态成员的特点
  • 280. 静态数据成员所有的同一类对象都使用一份数据 静态数据成员又称为类变量 它属于这个类,被该类的全体对象共享 类变量的初始化 class Counter { static int cnt; };类变量必须在class声明的外面单独声明,并初始化。如果不初始化,则编译器自动初始化0 int Counter::cnt; 或 int Counter::cnt = 0;
  • 281. 静态函数成员公共的静态函数成员就是一个全局函数 对公共的静态函数可以直接调用,不需要通过任何对象 静态成员函数中不得使用非静态数据成员
  • 282. 静态成员的应用例子 statics.cc#include using namespace std; class Cat { public: Cat(int age):itsAge(age){HowManyCats++; } virtual ~Cat() { HowManyCats--; } virtual int GetAge() { return itsAge; } virtual void SetAge(int age) { itsAge = age; } static int HowManyCats; private: int itsAge; }; int Cat :: HowManyCats = 0; void TelepathicFunction();
  • 283. 静态成员的应用例子 statics.ccint main() { const int MaxCats = 5; int i; Cat *CatHouse[MaxCats]; for (i = 0; i
  • 284. 友员为什么需要友员: Friend As Bridges. 什么东西可以成为友员 友员函数 友员类
  • 285. 友员的声明友员函数的声明 class Student { … friend void Register(Student&); … }; 友员类的声明 class Teacher; class Student { … friend class Teacher; };
  • 286. 友员的例子 friend.cc#include using namespace std; class beta; class alpha { private: int data; public: alpha(): data(3) { } friend int frifunc (alpha, beta); }; class beta { private: int data; public: beta () : data (7) { } friend int frifunc(alpha, beta); };
  • 287. 友员的例子 friend.ccint frifunc(alpha a, beta b) { return (a.data + b.data); } int main( ) { alpha aa; beta bb; cout << frifunc(aa, bb) << endl; return 0; }
  • 288. 成员函数的重载构造函数的重载 缺省构造函数 自定义构造函数 拷贝构造函数
  • 289. 构造函数的重载#include using namespace std; class Rectangle { public: Rectangle(); Rectangle(int width, int length); ~Rectangle() {} int GetWidth() const { return itsWidth; } int GetLength() const { return itsLength; } private: int itsWidth; int itsLength; }; Rectangle::Rectangle() { itsWidth = 5; itsLength = 10; }
  • 290. 构造函数的重载Rectangle::Rectangle (int width, int length) { itsWidth = width; itsLength = length; } int main() { Rectangle Rect1; cout << "Rect1 width: " << Rect1.GetWidth() << endl; cout << "Rect1 length: " << Rect1.GetLength() << endl; int aWidth, aLength; cout << "Enter a width: "; cin >> aWidth; cout << "\nEnter a length: "; cin >> aLength; Rectangle Rect2(aWidth, aLength); cout << "\nRect2 width: " << Rect2.GetWidth() << endl; cout << "Rect2 length: " << Rect2.GetLength() << endl; return 0; }
  • 291. Copy Constructor当由一个已有的对象来构造一个新的对象时,需要copy constructor 默认的对象拷贝 普通类的copy constructor C++编译器会自动给每一个类加上一个 如果没有使用任何动态空间,则可以使用系统的: 浅拷贝 (memcpy() will be called) 如果该类使用了任何动态分配的内存,则需要重载copy constructor 深拷贝 (need overload copy constructor)
  • 292. 调用copy constructor类A的定义如下 class A { int a; public: A(int v = 0) : a(v) {} }; 下面分别生成对象o1与o2有何不同 A o1(3); A o2 = o1; A o1(3); A o2; o2 = o1;A o2 = o1; 使用copy constructor A o2; o2 = o1; 使用赋值语句
  • 293. 拷贝构造函数的定义class A { int a; public: A(const A&); }; A::A(const A& o) { a = o.a; };
  • 294. 拷贝构造函数的例子class V { int *pv; public: V(int a) { pv = new int; *pv = a; } ~V( ) { delete pv;} void disp( ) { cout << "This=" << this << endl; cout << "pv=" << pv << endl; cout << "*pv=" << *pv << endl; } }; … V a(3); V b(5); a.disp(); b.disp();V a(3); V b = a; ...... *b.pv=100; a.disp( ); b.disp( );V(const V& s) { pv = new int; *pv = *s.pv; }
  • 295. 自动调用构造函数 问题出现 Class A{ int a; }; A oa = 3; 解决办法 class A { int a public: A(int i) : a(i) { }; }; int main() { A oa=3; }
  • 296. 自动调用的局限只会使用只含一个参数的constructor 任何时候遇到歧义,则放弃尝试
  • 297. 运算符的重载重载赋值运算符 重载运算符的方法 运算符作为友员来重新定义 作为成员函数来重载 运算符操作的返回 值返回 引用返回 重载转换运算符
  • 298. Operator=赋值操作符的功能 缺省的operator=
  • 299. 缺省的operator=的问题class V { int *pv; public: V(int a) { pv = new int; *pv = a} ~V( ) { delete pv;} void disp( ) { cout << "This=" << this << endl; cout << "pv=" << pv << endl; cout << "*pv=" << *pv << endl; } }; … V a(3); V b(5); a.disp(); b.disp();V a(3); V b(5); b = a; a.disp( ); b.disp( );
  • 300. Operator=的重载operator=作为成员函数重载 class V { … V& operator=(const V&); }; V& V::operator=(const V& s) { … *pv = *s.pv; return *this; };
  • 301. Operator=重载的注意事项可能的问题 obj = obj; 解决办法 if (this == &s) return *this; 编译器会自动为一个类创建operator= Memberwise assignment 复杂类必须自己定义operator=来处理堆内存的使用
  • 302. 异端的operator=重载class Pixel{ int x, y; int color; public: Pixel(int a=0, int b=0):x(a),y(b) {color=0;} Pixel(int a, int b, int c) { x = a; y = b; color = c; } void draw( ) { cout << "(" << x << "," << y << ")=" << color << endl; } }; … Pixel p1(1, 2); Pixel p2(3, 5, 1); p1.draw( ); p2.draw( );Pixel p1(1, 2); Pixel p2(3, 5, 1); p2 = p1; p1.draw( ); p2.draw( );Class Pixel { … Public: … Pixel& operator=(const Pixel& s) { x = s.y; y = s.x; color = !s.color; } };
  • 303. copy constructor与operator=什么时候调用copy constructor 什么时候调用operator = 指出下面三种写法的差别 A o; A o; o = A( ); A o1; A o2 = o1;A o; 直接调用constructor,构造对象o A o; o = A( ); 直接调用constructor ,构造对象o 再构造出一个临时对象,并将该临时对象赋给o, (operator= is called) A o1; A o2 = o1; 直接调用constructor ,构造对象o1 用o1作参数,再调用copy constructor构造对象o2
  • 304. 单目运算符的重载1operator ++作为友员的重载 class A { int a,b; public: A(int x, int y) : a(x), b(y) {} friend A& operator ++ (A&); }; A& operator ++ (A& x) { x.a ++; x.b ++; return x; }
  • 305. 单目运算符的重载2operator ++作为成员函数的重载 class A { int a,b; public: A(int x, int y) : a(x), b(y) {} A& operator ++ ( );//前++ }; A& A::operator ++ ( ) { a++; b++; return *this; }class A { int a,b; public: A(int x, int y) : a(x), b(y) {} A& operator ++ ( ); A operator++ (int );//后++ }; A A::operator++(int dummy) { A temp = *this; a++; b++; return temp; }
  • 306. 单加与单减的麻烦Prefix与postfix? ++a .vs. a++ C++的处理 前加为operator++(a) 后加为operator++(a,int) 使用一个int的哑元 前++为左值,应该返回一个引用 后++为右值,可以返回一个临时对象的值
  • 307. 双目运算符的重载1operator +作为友员的重载 class A { int a,b; public: A(int x, int y) : a(x), b(y) {} friend A operator + (const A&, const A&); }; A operator + (const A& x, const A& y) { int a = x.a + y.a; int b = x.b + y.b; return A(a,b); }
  • 308. 双目运算符的重载2operator +作为成员函数的重载 class A { int a,b; public: A(int x, int y) : a(x), b(y) {} A operator + (const A&); }; A A::operator + (const A& x) { return A(a+x.a, b+x.b); }
  • 309. 转换运算符用于将一个对象转换成其他数据类型 operator 类型名( ); 转换运算符没有返回类型 类型名即返回类型 转换运算符的声明与定义 class RMB { int y; int j; int f; public: operator double( ) { return y + j/10.0 + f/100.0; } };
  • 310. 流操作符<<的重载<<作为友员函数的重载 class A { int a,b; friend ostream& operator << (ostream&, const A&); }; ostream& operator << (ostream& oo, const A&x) { oo << "(" << x.a << "," << x.b << ")"; return oo; }
  • 311. 流操作符>>的重载>>作为友员函数的重载 class A { int a,b; friend istream& operator >> (istream&, A&); }; istream& operator >> (istream& ii, A&x) { char ch; ii >> ch; ii >> x.a; ii >> ch; ii >> x.b; ii >> ch; return ii; }
  • 312. 可以重载哪些东西?编译器为类自动生成的元素 Default constructor Default destructor Default copy constructor Default operator= 所有的运算符 不能重载的运算符: ·,·*,::,?:,sizeof, #,## 无法自己定义新的运算符
  • 313. 重载的要点Operator=只能当成员函数重载 只能是成员函数: =,( ),[ ],->,->*,类型转换函数 推荐的原则 所有一元运算符按成员函数来重载 建议以成员函数重载 +=,-=,/=,*=,^=,&=,|=,%=,>>=,<<= 其他二元运算符建议按友员重载
  • 314. rmb.h 程序#include #include #include using namespace std; class RMB{ private: int y, j, f; public: RMB(int, int, int); RMB(float); RMB(double); RMB(const RMB&); RMB operator+ (const RMB&); RMB operator- (const RMB&); RMB operator* (const int); RMB& operator= (const RMB&); operator float(); operator long(); friend ostream& operator<< (ostream&, const RMB&); friend istream& operator>> (istream&, RMB&); };
  • 315. rmb.cc 程序#include "rmb.h" RMB::RMB(int yuan, int jiao, int fen) { y = yuan; j = jiao; if(jiao >= 10) { y++; j -= 10; } f = fen; if(fen >= 10) { j++; fen -= 10; } } RMB::RMB(float a) { y = (int)a; j = (int)((a - y) * 10); f = (int)((100*a) - (100*y) - (10*j)); }
  • 316. rmb.cc 程序RMB::RMB(double a) { y = (int) a; j = (int) ((a - y) * 10); f = (int) (100*a - 100*y - 10*j); } RMB::RMB(const RMB& r) { y = r.y; j = r.j; f = r.f; } RMB RMB::operator+ (const RMB& r) { int x = y + r.y; int y = j + r.j; int z = f + r.f; if(z >= 10) { y++; z -= 10; } return RMB(x, y, z); }
  • 317. rmb.cc 程序RMB RMB::operator- (const RMB& r) { return RMB(y - r.y, j - r.j, f - r.f); } RMB RMB::operator* (const int n) { float x = (float) *this; cout << "x=" << x << endl; x *= n; cout << "x=" << x << endl; RMB t(x); cout << "t=" << t << endl; return t; } RMB& RMB::operator= (const RMB& r) { if(this == &r) return *this; y = r.y; j = r.j;
  • 318. rmb.cc 程序 f = r.f; return *this; } RMB::operator float() { return (float) (y + j / 10.0 + f / 100.0); } RMB::operator long() { return long(y * 100 + j * 10 + f); } ostream& operator<< (ostream& o, const RMB& r) { o << "Y" << r.y << "." << r.j << r.f << endl; return o; } istream& operator>> (istream& i, RMB& r) { float f; i >> f; r = RMB(f); return i; }
  • 319. rmbmain.cc 程序#include using namespace std; #include "rmb.h" int main() { RMB r1(3.26f); RMB r2(2.16f); RMB r3 = r1 + r2; RMB r4 = r2 - r1; RMB r5 = r1 * 3; cout << "r1 = " << r1 << endl; cout << "r2 = " << r2 << endl; cout << "r1 + r2 = " << r3 << endl; cout << "r1 - r2 = " << r4 << endl; cout << "r5 = " << r5 << endl; }
  • 320. Exercises设计一个字符串类String,要求该类能够完成以下操作(用函数重载完成) 要求:构造完整的类(构造、析构函数,拷贝构造函数,重载=操作符) 并且实现以下功能 String1=String2+String3 (重载+) String1 += String2 (重载+=) (int)String1 (重载类型转换int),将String对象中的所有字符的ASCII相加后返回。 String1 == String2 (重载相等判断,两字符串相等返回真,不等返回假) cout << String1 (输出符号重载) cin >> String1 (输入符号重载) 编写测试程序测试该类
  • 321. Q & AThank You!
  • 322. The C++ Programming Language Chapter 9
  • 323. I/O流I/O流
  • 324. 流的概念Stream
  • 325. 流的特点提供标准的I/O操作 支持缓冲 支持改向
  • 326. C++中的I/O标准流cin cout cerr clog iostream类库 /usr/local/include/c++/3.2 [UNIX] /usr/include/c++/3.2.2 [LINUX] http://www.cplusplus.com/ref/iostream/
  • 327. C++中I/O的结构iosistreamostreamfstreamiostreamifstreamofstream
  • 328. 标准I/O流cin cout cerr clog
  • 329. 标准流程序 myIO.cc#include using namespace std; int main( ) { char ch; cout << "Please enter some number." << endl; cin.get( ch ); cout << "ch=" << ch << "x" << endl; int i; float f; cin >> i >> f; cout << "i=" << i << endl; cout << "f=" << f << endl; }
  • 330. cin流A standard istream object Buffered, standard input Default is keyboard
  • 331. istream流的操作>>操作 get( ) getline( ) read( ) ignore( ) peek( ) putback( )
  • 332. >>操作>>的连续使用 为什么可以连续使用>>操作? >>的返回值 >>操作返回一个istream对象的引用 >>操作的重载功能
  • 333. get( )操作get( )操作 读取单个字符 返回一个整数 字符的ASCII码? get对回车换行的处理 get(char&)操作 读取单个字符 返回一个istream对象的引用
  • 334. getline( )操作读取一行 遇到回车键 返回istream对象的引用 getline()操作与>>的区别: char string1 [256], cin.getline(string1, 256); //get a whole line cin >> string1; //stop at the 1st blank space
  • 335. read( )操作read(buf, len) 返回一个istream对象的引用 多用于文件,对‘\n’照读不误: ifstream is("edata.dat", ios::binary); is.read( (char*) &Object, sizeof(Object));
  • 336. ignore( )操作ignore(len, delimiter) 忽略len个字符或者遇到‘\n’ cin.ignore(255, ‘\n’); //clear out the buffer
  • 337. peek( )与putback( )peek( )查看而不读取一个字符 if (cin.peek() == ‘*’) … Peek next character. Reads and returns the next character without extracting it from the stream. Returns EOF if stream is at the end of file and in any case where member good() (ios::good) would return false Parameters. none   Return Value.   The value of the next character in stream or EOF. putback( )向输入流中插入一个字符串 (必须和 istream::get(char&) 一起使用,否则流将不能使用) if (ch == ‘* ’) cin.putback(‘$’) ... Put the last character back to stream.   Decrements the next-character pointer for the input buffer if c was the last character got from the stream. Parameters. c -- The character to put back. Must have the same value as the last character extracted. Return Value.   The function returns *this
  • 338. ifstream文件流输入 将一个文件打开,并按流的方式输入 初始化一个ifstream流对象 ifstream fin("MyFile.txt"); 文件流的操作 >>操作 fin.get( ch ) //char ch fin.getline(buffer, MAX ) //char buffer[MAX] …
  • 339. 文件输入的例子ifstream myfin("myfile.txt"); char line[120]; int myInt = 0; … myfin.getline(line, 120); myfin >> myInt; … myfin.close( );
  • 340. 使用ifstream的fin.cc#include #include using namespace std; int main() { ifstream inf("test.txt"); char buf[200]; inf.getline(buf, 200); cout << "buf = " << buf << endl; int i; inf >> i; cout << "i = " << i << endl; char ch; ch = inf.get( ); cout << "ch = " << ch << endl; ch = inf.get( ); cout << "ch = " << ch << endl; inf.close( ); }
  • 341. 使用ifstream的fwc.cc#include using namespace std; #include int main(int argc, char** argv) { ifstream fin( argv[1] ); char line[100]; int cnt = 0; do { cnt ++; fin >> line; } while ( !fin.eof() ); cout << "Total words : " << cnt-1 << endl; fin.close( ); }
  • 342. cout流A standard ostream object Buffered, standard output Default is screen
  • 343. ostream的操作operator << put( ) write( ) width( ) fill( ) setf( )
  • 344. <<操作<<的连续使用 为什么可以连续使用<<操作? <<的返回值 <<操作返回一个ostream对象的引用 <<操作的重载功能
  • 345. put( )操作put( )操作 输出单个字符 返回一个ostream对象的引用 cout.put(‘H’).put(‘i’);
  • 346. write( )操作write(buf, len) write( )返回一个ostream对象的引用 cout.write (buf, len) //char buf[len]
  • 347. width( )操作输出的默任宽度 cout.width(10); cout << 123.4 << endl; //C:> 123.4 cout << 123 << endl;
  • 348. fill( )操作按width( )操作所定的宽度,对于指定用于填充空档位的字符 cout.width(10); cout.fill(‘#’); cout << 123.456 << endl; //C:>##########123.456 cout << 123 << endl;
  • 349. setf( )操作设输出标志操作 常见的输出控制标志 : cout.setf(ios::left) ios::left ios::right ios::dec ios::oct ios::hex ios::showbase ios::showpoint ios::uppercase ios::showpos ios::scientific
  • 350. 格式化输出1特殊字符 \n (new line) \r (return) \t \\ \a (bell)
  • 351. 格式化输出2输出控制符 flush: clear out buffer endl: insert a ‘\n’, and clear out buffer oct: set the output as oct. dec hex
  • 352. ofstreamofstream(fileName, mode) ios::app : start writing at end of file ios::ate: start reading or writing at end of file Ios::in : open for reading ios::trunc: truncate file to zero length if it exists ios::nocreate : error when opening if file does not exist ios::noreplace: error when opening for output if file exists. ios::binary: open file in binary mode. ios::out : open for writing E.g. fstream file; file.open("Group.dat", ios::app | ios:: out | ios::in | ios::binary);
  • 353. 文件输出的例子 fOut.cc#include #include using namespace std; int main( ) { ofstream fout("test.txt"); int k; char buf[50]; fout << "This is a text file." << endl; cout << "Please enter a number:"; cin >> k; fout << "The number you entered is " << k << endl; cout << "Please enter a word:"; cin >> buf; fout << "The word you entered is: " << buf << endl; fout.close( ); }
  • 354. 程序ifof.cc#include using namespace std; #include char convert(char c) { if ((c >= '0')&&(c <= '9')) return '#'; if ((c >='A')&&(c <= 'Z')) { return c+32; } if ((c >= 'a')&&(c <= 'z')) { return c - 32; } return c; }
  • 355. 程序ifof.ccint main(int argc, char** argv) { ifstream fin( argv[1] ); ofstream fout( argv[2] ); for( ; ; ) { char ch = fin.get( ); if ( !fin.eof() ) fout << convert( ch ); else break; }; fin.close( ); fout.close( ); }
  • 356. 对对象的文件操作将一个对象写入一个文件 从文件中读入并恢复一个对象:
  • 357. 程序 obFile.cc#include #include using namespace std; class Animal { public: Animal(int weight,long days):itsWeight(weight),DaysAlive(days){} ~Animal(){} int GetWeight()const { return itsWeight; } void SetWeight(int weight) { itsWeight = weight; } long GetDaysAlive()const { return DaysAlive; } void SetDaysAlive(long days) { DaysAlive = days; } private: int itsWeight; long DaysAlive; };
  • 358. 程序 obFile.ccint main(int argc, char *argv[]) // returns 1 on error { if (argc != 2) { cout << "Usage: " << argv[0] << " " << endl; return(1); } ofstream fout(argv[1],ios::binary); if (!fout) { cout << "Unable to open " << argv[1] << " for writing.\n"; return(1); } Animal Bear(50,100); fout.write((char*) &Bear,sizeof Bear); fout.close();
  • 359. 程序 obFile.cc ifstream fin(argv[1],ios::binary); if (!fin) { cout << "Unable to open " << argv[1] << " for reading.\n"; return(1); } Animal BearTwo(1,1); cout << "BearTwo weight: " << BearTwo.GetWeight() << endl; cout << "BearTwo days: " << BearTwo.GetDaysAlive() << endl; fin.read((char*) &BearTwo, sizeof BearTwo); cout << "BearTwo weight: " << BearTwo.GetWeight() << endl; cout << "BearTwo days: " << BearTwo.GetDaysAlive() << endl; fin.close(); return 0; }
  • 360. Reference URLhttp://www.cppreference.com This URL contains a lot of functions reference pages, such as standard C Library, iostream library and STL library.
  • 361. Exercises 定义一个Dog类,包含体重和年龄两个数据成员及相应的成员函数。声明一个实例dog1,体重为5,年龄为10,使用I/O流把dog1的状态写入磁盘文件(文件名称从键盘输入获得):再声明另一个实例dog2,通过读文件把dog1的状态赋给dog2 从键盘读入字符串,并将它们写入磁盘(以追加方式 ios::app)。当用户输入‘~’字符时,程序停止。
  • 362. Q & AThank You!
  • 363. The C++ Programming Language Chapter 10
  • 364. Exception异常,意外,出错 程序常见问题介绍 错误的类型 人为的 客观的 错误的处理方法 传统的 异常方式
  • 365. bulletproofBugs Programmer made mistake Logic error Programmer misunderstand the problem or solution Exception Unusual but predictable.
  • 366. 异常异常的特点 客观存在,不能消灭 但能够预测并有选择性的去处理 You can prepare for them.
  • 367. 典型的异常你知道计算机可能会耗光内存 当没有更多内存空间时,你: 死机 通知用户并退出程序 通知用户并让用户来处理 采取适当的纠正行动,让用户不受干扰
  • 368. C++提供的异常处理机制Exception是一个对象 出现意外的地方将会产生一个异常:抛出一个异常对象 该对象被传递到负责意外处理的地方 由负责意外处理的代码专门进行统一的异常处理 异常对象包含有意外发生的详细信息
  • 369. 常见的异常常见的异常比如: 内存请求失败 文件操作不成功 异常的发生都在程序的较底层 异常的表现都在较高层,对异常的处理逻辑也都在较高层面,特别是直接与用户打交道的代码。 异常提供了一个快速的通道,把异常信息从其发生的地方直接传递到对意外进行处理的地方
  • 370. 异常的产生任何时候,程序在执行中遇到了非正常状况都可以抛出异常 异常用throw语句抛出 A *p = new A( ); if (p == NULL) { throw "Out of Memory."; } 一旦抛出异常,则程序将在throw语句处跳出
  • 371. 异常的捕捉异常也由程序员负责捕获 用try{…}catch( ){…}语句来捕获异常 没有捕获的异常将被忽略try { }catch(OutOfMemory) { … }catch(FileNotFound) { … }
  • 372. 异常的传递产生异常之后,程序会立刻跳转 跳出到最近的一层捕获异常的语句 如果当前没有捕获语句或者捕获语句中没有匹配的异常,则程序会跳出当前的函数 在函数的调用处,如果没有捕获住异常,则直接跳转到更高一层的调用者 如果一直没有捕获该异常,C++将会使用默认的异常处理函数 该处理函数可能会让程序最终跳出main函数并导致程序异常终止
  • 373. 抛异常的例子#include using namespace std; int main( ) { int a, b; a = 8; b = 4; double c = a/b; cout << c << endl; }a = 8; b = 0; c = a/b;… if (b == 0) throw "Divided by Zero!"; else { double c = a/b; cout << c << endl; }
  • 374. 捕获异常#include using namespace std; int main( ) { int a, b; a = 8; b = 4; try{ if (b == 0) throw "Divided by Zero!"; else { double c = a/b; cout << c << endl; } }catch(…) { cout << "Exception caught!" << endl; } }
  • 375. 异常传递的例子#include using namespace std; void f1( ) { … throw "A exception."; … } void f2( ) { f1( ); } int main() { … f2(); … }
  • 376. 多层异常的捕获try { }catch(OutOfMemory) { … }catch(FileNotFound) { … }catch(…) { … }
  • 377. 捕捉异常的形参与值多重catch语句 异常匹配的顺序 异常对象的添值
  • 378. 异常的类型异常就是一个对象 异常也会有类型
  • 379. 自定义异常用户自定义的异常
  • 380. 自定义异常的例子自己定义OutOfRang类 并抛出一个OutOfRang对象作为异常
  • 381. 程序array.cc……………. int& MyArray::operator[ ] (int idx) { if ((idx >= max)||(idx < 0)) { //throw "OutOfRange"; throw new OutOfRange(max, idx); }else return pV[idx]; } ………………..
  • 382. Inner class定义在一个类里面的类 异常类常封装为inner class
  • 383. Inner class example excpt.cc#include using namespace std; class MyClass { int score; public: class innerE { int val; char msg[100]; public: innerE(char* s, int v=0){ strcpy(msg, s);val=v;} void disp( ) { cout << msg <<": "<100) score=0; } void disp( ) { cout << score << endl; } void set( int s ){ if(s<0||s>100)throw innerE("not a proper score",s); score = s; } };
  • 384. Inner class example excpt.ccint main( ) { MyClass mc; try { mc.disp(); mc.set(120); mc.disp(); } catch(MyClass::innerE e) { e.disp( ) ; } }
  • 385. Exercises定义一个myArray的类,要求重载operator[]用于检查给进来的参数是不是超过数组的界限,如果是的话,抛出一个异常,否则返回相应的值的引用。 operator[] 重载的原型 int& operator[ ] (int index) { …. …. } 编写一个程序测试异常。 提示:异常可以写成inner class,也可以写成outer class。
  • 386. Q & AThank You!
  • 387. The C++ Programming Language Chapter 11
  • 388. 重要数据结构链表: 它由设计为大小合适的小的容器组成, 这些容器可根据需要链接在一起。 链表组件:链表由节点组成。每个节点内可放置指定的数据类型。 头节点: 其工作是管理链表的头。 尾节点: 初始时,头节点的 myNext 指针指向尾节点。 内部节点:存放数据类型。 myHead myNext链表头节点尾节点
  • 389. 链表的特点非常重要的数据结构 在计算机系统中有广泛的应用 灵活 比数组节省空间 访问比较慢 操作比较复杂
  • 390. 链表使用结构与指针可以实现链表 一个典型的链表 节点 链表头header
  • 391. 链表Flexible space use Dynamically allocate space for each element as needed Include a pointer to the next item Linked list Each node of the list contains the data item (an object pointer in our ADT) a pointer to the next nodeDataNextobject
  • 392. 链表Collection structure has a pointer to the list head Initially NULL Collection Head
  • 393. 链表Collection structure has a pointer to the list head Initially NULL Add first item Allocate space for node Set its data (may be pointer to object) Set Next to NULL Set Head to point to new node HeadCollectionnodeDataNextobject
  • 394. 链表Add second item Allocate space for node Set its data pointer to object Set Next to current Head Set Head to point to new nodeDataNextobjectnodeDataNextobject2nodeHeadCollection
  • 395. 链表通常的节点类型构成链表显然离不开指针 链表的定义 struct Person { char name[20]; unsigned int age; char address[100]; Person *next; };
  • 396. 链表的操作1取头 取尾 取下一个节点 增加一个节点 插入一个节点 删除一个节点 查找某一个节点
  • 397. 链表的操作2链表的建立 链表的删除
  • 398. 基本链表的操作与实现插入节点 (high efficient) 删除节点 (same as search in O(N)). No need to fill "holes"like array deletion. 建立与删除链表 查找一个节点 (O(N)) 更新一个节点 In general, a linked list has almost the same efficiency as a non-ordered array for above operations.
  • 399. 一个整数型的链表的例子节点 struct Node{ int v; Node *next; }; 操作 Insert Delete
  • 400. 实现该链表 linklist.cc#include using namespace std; struct Node { int V; Node *next; }; Node *header = NULL; void Insert(Node *pNode) { pNode->next = header; header = pNode; }void Delete(Node *pNode) { if ((pNode == NULL)||(header == NULL)) return; if (pNode == header) { header = header->next; delete pNode; return; } Node *prev = header; while (prev->next != pNode) if (prev->next == NULL) break; else prev = prev->next;
  • 401. 实现该链表 linklist.cc if (prev->next != NULL) { prev->next = pNode->next; delete pNode; } } int main( ) { cout << "Please enter 10 numbers:" << endl; for(int i=0; i<10; i++) { int num; cin >> num; Node* ptr = new Node; ptr->V = num; ptr->next=NULL; Insert(ptr); }
  • 402. 实现该链表 linklist.cc Node *ptr = header; while(ptr != NULL) { cout << ptr->V << ", "; ptr = ptr->next; } cout << endl; //ptr = header; while(header)//while(ptr != NULL) { Delete(header);//Delete(ptr); //ptr = header; } } //end linklist.cc
  • 403. Another example linklist2.cc#include using namespace std; class CLink { class Node { char ch; Node *next; public: Node(char c) { ch = c; next = NULL; } Node* GetNext( ) { return next; } void SetNext(Node *ptr) { next = ptr; } char GetChar( ) { return ch; } }; Node* head; Node* cur; public: CLink( ) { head = cur = NULL; }
  • 404. Another example linklist2.cc char GetHead( ) { cur = head; if (head != NULL) { return head->GetChar(); }else { return '\0'; } } char GetNext( ) { if (cur == NULL) return '\0'; cur = cur->GetNext(); return (cur != NULL)? cur->GetChar( ):'\0'; } void AddNode(char c) { Node* p = new Node(c); p->SetNext(head); head = p; }
  • 405. Another example linklist2.cc~CLink( ) { Node *p; while(head != NULL) { p = head->GetNext( ); delete head; head = p; } } }; int main( ) { cout << "Please enter a string:" << endl; char ch; CLink mylink; while((ch=cin.get()) != '\n') { mylink.AddNode(ch); } cout << mylink.GetHead(); while((ch=mylink.GetNext()) != '\0') { cout << ch; } cout << endl; }
  • 406. 变化了的链表双向链表 struct Node{ int v; Node *prev; Node *next; }; headtailprevprevprev
  • 407. 变化了的链表Class Dlinklist { Node * head; Node * tail; public: Dlinklist() { head = NULL; tail = NULL; } void insertFirst(int d); void insertLast(int d); void deleteFirst(); bool isEmpty(); void display(); } …………….. You will be asked to implement above functions in your assignment.
  • 408. Q & AThank You!
  • 409. The C++ Programming Language Chapter 12
  • 410. 栈栈介绍pushpop
  • 411. 堆栈的特点先进后出,后进先出 在一个线性的存储空间中如何实现这种特殊的LIFO操作?
  • 412. 栈的操作将一个元素压入栈中push( ) 从栈中取出一个元素pop( ) 判断栈有没有元素empty( ) 问栈中还有几个元素count( ) 将栈中的所有元素清空clear( ) 初始化一个栈reset( )
  • 413. 栈的应用栈在函数调用中的作用 栈被广泛的应用在编译器中
  • 414. 栈的实现栈的基本原理是一致的 栈的具体实现是多种多样的 典型的栈的实现 用数组来实现一个栈 用链表来实现一个栈
  • 415. 用数组实现一个字符栈 cstack.cc#include using namespace std; class cstack { char v[200]; int cur; public: cstack( ); int push(char); char pop( ); bool isempty( ); void reset( ); };
  • 416. 用数组实现一个字符栈 cstack.cccstack::cstack( ) { cur = 0; } int cstack::push(char i) { v[cur++] = i; return cur; } char cstack::pop( ) { return v[--cur]; } bool cstack::isempty( ) { if (cur > 0) return false; else return true; } void cstack::reset( ) { cur = 0; }
  • 417. 用数组实现一个字符栈 cstack.ccint main( ) { cstack stk; cout << "Please enter a string:" << endl; char ch; do { ch = cin.get( ); stk.push( ch ); } while (ch != '\n'); while ( !stk.isempty() ) cout << stk.pop(); cout << endl; }
  • 418. 用链表实现一个字符栈This is your assignment.
  • 419. QueueFIFO: First in, First out.toptailpop( )insert( )
  • 420. 封装一个 Queue: myqueue.cc#include using namespace std; struct node { int data; node* next; node(int n, node* p=NULL) : data(n), next(p) { } node() : next(NULL) { } };
  • 421. 封装一个 Queue: myqueue.ccclass Queue { private: node* top; node* tail; public: Queue() { top = NULL; tail = NULL; } ~Queue(); void insert(int); int pop(); bool empty( ) { return top == NULL;} };
  • 422. 封装一个 Queue: myqueue.ccvoid Queue::insert(int n) // insert new node at tail of list { node* temp = new node(n, NULL); if (tail == NULL) tail = top = temp; else { tail -> next = temp; // insert after existing tail node tail = temp; } }
  • 423. 封装一个 Queue: myqueue.ccint Queue::pop() { node* fetch = top; // copy of top if (fetch != NULL) { top = fetch -> next; int x = fetch -> data; delete fetch; return x; } else { cout << "ERROR: Queue EMPTY!\n"; return 0; } }
  • 424. 封装一个 Queue: myqueue.ccQueue::~Queue() { int count = 0; while (top != NULL) { node* dead = top; top = top -> next; delete dead; count++; } cout << "Queue destroyed, " << count << " nodes deleted\n"; }
  • 425. 封装一个 Queue: myqueue.ccint main () { Queue q; q.insert(2); q.insert(4); q.insert(6); q.insert(8); while ( ! q.empty() ) cout << q.pop() << endl; cout << "That\'s all the queue\n"; return 0; }
  • 426. 用 stack 封装成一个 QueueThis is your assignment …
  • 427. Binary TreesWhy use binary trees? It combines the advantage of two other structures: an sorted array and a linked list. Quick search, insert, and delete items.
  • 428. Binary TreesWhat is a tree? A tree consists of nodes connected by edges. A tree example:nodesedges
  • 429. Binary TreesWhat is a binary tree? Every node in a tree can have at most two children. What is a binary search tree? A node’s left child must have a key less than its parent. A node’s right child must have a key greater than or equal to its parent.
  • 430. Binary Search Trees53304739914342372618479
  • 431. Binary Search TreesBinaryTree. h #include using namespace std; class BinaryNode { int iData; BinaryNode* left; BinaryNode* right; public: BinaryNode( const int theData, BinaryNode *lt=NULL, BinaryNode *rt=NULL ) : iData( theData), left( lt ), right( rt ) { } friend class BinarySearchTree; };
  • 432. Binary Search Treesclass BinarySearchTree { private: BinaryNode* root; void add(const int x, BinaryNode* t); void makeEmpty(BinaryNode* t) const; void printTree( BinaryNode* t ) const; public: BinarySearchTree( ) { root = NULL; } BinarySearchTree( const BinarySearchTree & rhs ); ~BinarySearchTree( );
  • 433. Binary Search Trees BinaryNode* getRoot() const { return root; } BinaryNode* find( const int key) const; void insert( const int x ); void printTree( ) const; void preOrder(BinaryNode* t); void inOrder(BinaryNode* t); void postOrder(BinaryNode* t); };
  • 434. Binary Trees Show the procedure to find a node: Show the procedure to insert a node: Traversing a binary search tree: Inorder traversal: A + B * C Preorder traversal: *A + BC Postorder traversal: ABC * + +*BCA
  • 435. Thank You!
  • 436. The C++ Programming Language Chapter 13
  • 437. 什么是算法算法是在有限步骤内求解某一问题所使用的一组定义明确的规则。 通俗点说,就是计算机解题的过程。在这个过程中,无论是形成解题思路还是编写程序,都是在实施某种算法。前者是推理实现的算法,后者是操作实现的算法。
  • 438. 什么是算法一个算法应该具有以下五个重要的特征: 有穷性: 一个算法必须保证执行有限步之后结束; 确切性: 算法的每一步骤必须有确切的定义; 输入: 一个算法有0个或多个输入,以刻画运算对象的初始情况,所谓0 个输入是指算法本身定义了初始条件; 输出: 一个算法有一个或多个输出,以反映对输入数据加工后的结果。没有输出的算法是毫无意义的; 可行性: 算法原则上能够精确地运行,而且人们用笔和纸做有限次运算后即可完成。
  • 439. 什么是算法算法的复杂性(the time complexity)是算法效率的度量,是评价算法优劣的重要依据。 一个算法的复杂性的高低体现在运行该算法所需要的计算机资源的多少上面,所需的资源越多,我们就说该算法的复杂性越高;反之,所需的资源越少,则该算法的复杂性越低。
  • 440. 算法分析基础简化的计算模型 算法分析的表示方法: Most of the algorithms apply directly to specific data structures. Insert a new data item. Search/delete for a specified item. Iterate/sort all the items in a data structure. 重要的算法介绍 查找与排序
  • 441. 算法分析分析什么 确定与检验程序正确与否 运行速度 程序的复杂性 程序的可靠性 使用内存的大小 代码的size 对于任意给定的问题,设计出复杂性尽可能低的算法是我们在设计算法时追求的一个重要目标;另一方面,当给定的问题已有多种算法时,选择其中复杂性最低者,是我们在选用算法适应遵循的一个重要准则。
  • 442. 程序的性能hardware The programming language used The compiler used The OS
  • 443. 计算模型存取操作 赋值操作 函数调用 函数返回
  • 444. 运行效率平均运行时间 最佳与最差的运行情况 Big O Notation: in computer science, it’s useful to have a shorthand way to say how efficient a computer algorithm is. A linear search: O(N) A binary search: O(logN)
  • 445. Big O NotationN (items)Number of stepsO(N )2O(N)O(logN)
  • 446. 算法分析的表示法大O表示方法:渐进上界法 渐进原理 一种算法所花的时间肯定比某种已知的少 大表示方法:渐进下界法
  • 447. 算法设计策略常用的算法设计策略有: 蛮力法---- 穷举所有可能性。 递归技术 —— 最常用的算法设计思想,体现于许多优秀算法之中。 分治法 —— 分而制之的算法思想,体现了一分为二的哲学思想。 模拟法 —— 用计算机模拟实际场景,经常用于与概率有关的问题。 贪心算法 —— 采用贪心策略的算法设计。 优化法----- 利用生物学优选原理。
  • 448. 排序常用的重要排序方法 选择排序法 : O(N2 ) 冒泡排序法 : O(N2 ) 插入排序法 : O(N2 ) 快速排序法: O( N * logN )
  • 449. 选择排序最直接的排序方法 每次选择一个最大(最小)的元素放到应该的位置
  • 450. 冒泡排序法多轮排序 每轮都要比较所有相邻的数据对 将数据对按单一方向交换(由升序与降序决定交换方向) 直到最后,所有的数据都已经排好了顺序 见p-134的冒泡排序
  • 451. 插入排序法将头两个元素排序 接下来依次将每一个元素排到正确的位置 直到所有的元素都排完
  • 452. 快速排序法1效率最高的排序方法 选出一个分界值,把数组分成两个部分 大于等于分界值的元素集中到数组的某一部分,小于分界值的元素集中到另一部分 对于分成的两个部分分别再做同样的操作
  • 453. 快速排序法2对于如下13个元素V[] 9 8 7 5 4 3 1 2 6 0 11 9 1 选最左边的元素值为pivot 下标l从左往右 如果V[l]>pivot,则停止 下标r从右往左 如果V[r]<=pivot,则停止 将V[l]与V[r]的值交换 继续,直到l>=r 将pivot与V[r]交换 对于两个集合(left, r-1)与(r+1, right)递归
  • 454. 高级算法Optimization algorithms: Genetic algorithm: A genetic algorithm (GA) is an algorithm used to find approximate solutions to difficult-to-solve problems, inspired by and named after biological processes of inheritance, mutation, natural selection, and the genetic crossover that occurs when parents mate to produce offspring.
  • 455. 高级算法 Neural Network: An artificial neural network, more commonly known as a neural network, is a mathematical model for information processing based on a connectionist approach to computation. The original inspiration for the technique was from examination of bioelectrical networks in the brain formed by neurons and their synapses. In a neural network model, simple nodes (or "units", "neurons") are connected together to form a network of nodes - hence the term "neural network".
  • 456. NP and NP-hard problems A problem is assigned to the NP (nondeterministic polynomial time) class if it is verifiable in polynomial time by a nondeterministic Turing machine. A problem is NP-hard if an algorithm for solving it can be translated into one for solving any other NP-problem . Examples of NP-hard problems include the Hamiltonian cycle and traveling salesman problems.
  • 457. Q & AThank You!
  • 458. The C++ Programming Language Chapter 14
  • 459. STL与自定义模板 STL 自定义模板
  • 460. 模板模板简介 模板的特点 A "parameterized types" STL was adopted into the definition of C++ 给予编译器学习的能力,教会它产生新的类型
  • 461. 模板与实例化模板是对所有类型所下的一种定义 使用时必须要对它实例化
  • 462. 自定义函数模板,类模板的格式函数模板: template < 类型形参 > 返回类型 FunctionName (形参 ) { //……. } 类模板: template <类型形参 > class className { //….. }; template <类型形参 > 返回类型 className <类型名表 > ::MemberFunction1(形参 ) { //….. }
  • 463. 简单的函数模板template T Max(T a, T b) { return (a>b ? a : b); } int main( ) { cout << "max(5, 2)=" << Max(5, 2) << endl; cout << "max(a, b)=" << Max(‘a’, ‘b’) << endl; }
  • 464. 函数模板的重载template T Min(T a, T b) { return (a>b ? b : a); } char * Min(char* a, char* b) { return (strcmp(a,b)>0 ? b : a); } int main( ) { cout << "min(5, 2)=" << Min(5, 2) << endl; cout << "min(a, b)=" << Min("abc", "xyz") << endl; }
  • 465. 完整的Array类模板与Disp函数模板1#include using namespace std; const int DefaultSize = 10; template class Array { public: Array(int itsSize = DefaultSize); Array(const Array &rhs); ~Array() { delete [] pType; } Array& operator=(const Array&); T& operator[](int index) { return pType[index]; } int getSize() { return itsSize; } private: T *pType; int itsSize; };
  • 466. 完整的Array类模板与Disp函数模板2template Array::Array(int size): itsSize(size) { pType = new T[size]; for (int i = 0; i Array::Array(const Array &rhs) { itsSize = rhs.GetSize(); pType = new T[itsSize]; for (int i = 0; i
  • 467. 完整的Array类模板与Disp函数模板3template Array& Array::operator=(const Array &rhs) { if (this == &rhs) return *this; delete [] pType; itsSize = rhs.GetSize(); pType = new T[itsSize]; for (int i = 0; i
  • 468. 完整的Array类模板与Disp函数模板4template void Disp( Array& theArray) { for(int j=0; j
  • 469. 完整的Array类模板与Disp函数模板5int main( ) { Array theArray; Array theString; for (int i = 0; i < theArray.getSize(); i++) { theArray[i] = i*2; theString[i] = 'A' + i; } Disp( theArray ); cout << endl; Disp( theString ); }
  • 470. STL简介STL被接纳为C++的一部分 作为编译器的一部分 什么是STL Template based container classes Sequence, associative, etc Some common algorithm Sorting, searching Tested, debugged, high performance and free Reusable STL components: Containers Algorithms Iterators
  • 471. Containers容器的特点 包含其他对象的对象 存储方式 直接存储 容器中有一份对象的拷贝 占空间,一个对象不能放入多个容器,不能包含本身 间接存储 容器只保存对象的指针 对对象的存取通过引用一个指针
  • 472. Sequence Containersvector 类似于数组,但更安全 能自动增长 list 对于频繁的插入与删除做了优化 deque vector 的子类, 但可从头,尾两端操作。
  • 473. vector一个同类元素的有序序列 类似于数组,但更强大,更安全 template > class vector { … }; vector中的元素能够自动增长 vector的使用 #include vector< int > vInts; vector< float > vFloats; vector< Student > softClass(50);
  • 474. vector的操作[ ] //按下标取元素 front() //取第一个元素 back() //取最后一个元素 at() //比较安全的[],能抛出out_of_range异常 insert() //在给定的位置插入一个或多个元素 pop_back() //删除最后一个元素 erase() //删除一个或多个元素
  • 475. 能放在vector中的对象要支持默认的构造函数 无参数的构造函数 支持拷贝构造函数 支持重载赋值操作 vector适合按下标存取元素的需求
  • 476. vector的使用#include … vector iV(10); for(int i=0; i<10; i++) iV[i] = 2*i; vector::iterator ci = iV.begin(); ci += 2; iV.insert( ci , 888); for(ci=iV.begin( ); ci!=iV.end( ); ci++) cout << *ci << endl;
  • 477. list与vector类似,也是一个有序的列表 对插入与删除操作进行了优化 对元素的访问可通过iterator来进行 list iList; list::const_iterator ci = iList.begin(); cout << *(++ci);
  • 478. list的操作push_front() //在列表头部增加元素 pop_front() //在列表头部删除元素 push_back() //在列表尾部增加元素 pop_back() //在列表尾部删除元素 list可以双向增长 list适合对元素频繁的插入与删除的应用
  • 479. list的使用#include … list iL; list::iterator ip = iL.begin(); for(i=0; i<10; i++, ip++) iL.insert( ip, i*10); //is this in order? iL.sort( ); ip = iL.begin(); while( ip != iL.end() ) { cout << *ip << ":"; ip ++; }
  • 480. 程序lstack.cc#include #include using namespace std; class lstack { list vc; list::iterator v; public: lstack(); lstack(char); char push(char); char pop(); void disp(); }; lstack::lstack(){ } lstack::lstack(char a) { v = vc.begin(); vc.insert(v, a); }
  • 481. 程序lstack.ccchar lstack::push(char a) { v = vc.begin(); vc.insert(v, a); } char lstack::pop() { char b; if(!vc.empty()) { v = vc.begin(); b = *v; vc.pop_front(); } return b; } void lstack::disp() { for(v = vc.begin(); v != vc.end(); v++) cout << *v << endl; }
  • 482. 程序lstack.ccint main() { lstack ls; cout << "The push is: " << endl; for(int i = 0; i < 5; i++) ls.push('a' + i); ls.disp(); cout << "The pop is: " << endl; for(int i = 0; i < 5; i++) ls.pop(); ls.disp(); }
  • 483. Special ContainersContainer Adapters: adapt to STL standard containers. Stack Queue Priority queues
  • 484. Stack adapter example stackSTL.cc#include #include using namespace std; int main() { stack st; st.push(1); st.push(2); st.push(3); cout << st.top() << ‘ ‘ ; st.pop(); st.top() = 77; st.push(4);
  • 485. Stack adapter example stackSTL.cc while(!st.empty()) { cout << st.top() << ‘ ‘; st.pop(); } cout << endl; }
  • 486. Queues adapter queueSTL.cc#include #include #include using namespace std; int main() { queue q; q.push("Hello"); q.push("world"); cout << q.front(); q.pop(); cout <
  • 487. Associative Containersvector,list 的特点 有序的元素集合 按顺序或者按下标存取 无法按关键字存取 Associative containers的特点 map multimap set multiset
  • 488. map可按关键值实现快速存取的容器 每个元素是一个对 key必须是唯一的
  • 489. map的使用Map可按照key去取值 map softClass; Student Jack("Jack", 20); softClass["Jack"] = Jack; Student Lisa = softClass["Lisa"]; 也可使用iterator操作 map< string, Student >::const_iterator ci = softClass.begin(); cout << ci->first; //print Key value cout << ci->second; //print Student object
  • 490. map的例子#include … map iM; iM.insert(map::value_type("ABC", 100)); iM.insert(map::value_type("XYZ", 200)); map::const_iterator mp = iM.begin(); while( mp != iM.end() ) { cout << mp->first << " : " << mp->second << endl; mp ++; } int ia = iM["ABC"]; int ib = iM["XYZ"];
  • 491. multimap类似于map 但关键值可以不唯一,多个元素可有相同的关键值
  • 492. multimap的例子#include … multimap iM; iM.insert(multimap::value_type("CXP", 100)); iM.insert(multimap::value_type("CXP", 200)); multimap::const_iterator mp1; multimap::const_iterator mp2; mp1 = iM.upper_bound("CXP"); mp2 = iM.lower_bound("CXP"); multimap::const_iterator mp; for(mp = mp2; mp!=mp1; mp++) cout << mp->first << " : " << mp->second << endl;
  • 493. set与map相似 但元素不是对 一个元素就是一个唯一的key 即使插入重复的值,set将只保存一份
  • 494. set的例子#include … set iS; iS.insert(1); iS.insert(2); iS.insert(3); iS.insert(5); iS.insert(3); set::const_iterator sp = iS.begin(); for(; sp!=iS.end(); sp++) cout << *sp << endl;
  • 495. multiset与set类似 但容许重复的值
  • 496. multiset的例子#include … multiset iMS; iMS.insert(1); iMS.insert(2); iMS.insert(3); iMS.insert(5); iMS.insert(3); multiset::const_iterator msp = iMS.begin(); for(; msp!=iMS.end(); msp++) cout << *msp << endl;
  • 497. 相关的信息查看类模板的头文件 /usr/local/include/c++/3.2/
  • 498. STL AlgorithmsSTL provides some standard algorithms: Search : for_each(), find(), find_first_of(), find_end()… Sort: sort(), reverse() … Copy: copy(), copy_backward()… Modify: replace(), merge(), remove()… Numeric: min(), max(), count(), swap(), accumulate()… …… Algorithms usually work with STL Iterators together.
  • 499. STL Algorithms examples myFind.cc#include #include using namespace std; int arr[ ] = {11, 22, 33, 44, 55, 66, 77, 88}; int main() { int* ptr; ptr = find(arr, arr+8, 33); cout << "First object with value 33 at offset: " << (ptr-arr) << endl; }
  • 500. STL Algorithms examples myCount.cc#include #include using namespace std; int arr [ ] = {33, 22, 33, 44, 33, 55, 66,77}; int main() { int n = count(arr, arr+8, 33); cout << " there are " << n << " 33’s in arr. " << endl; }
  • 501. STL Algorithms examples patternSTL.cc#include #include using namespace std; int source[ ] = { 11, 44, 33, 11, 22, 33 ,11, 22, 44}; int pattern[ ] = { 11, 22, 33}; int main() { int* ptr; ptr = search(source, source+9, pattern, pattern+3); if(ptr == source+9) cout << " No match found\n"; else cout << "Match at " << (ptr – source) << endl; }
  • 502. STL Algorithms examples: in_to_cm.cc#include #include using namespace std; void in_to_cm(double); int main() { double inches[ ] = {3.5, 6.2, 1.0, 12.75, 4.33}; for_each(inches, inches+5, in_to_cm); cout << endl; } void in_to_cm(double in) { cout << (in * 2.54) << " "; }
  • 503. Q & AThank You!
  • 504. The C++ Programming Language Core C++ Test
  • 505. Q & AThank You!