Download presentation
Presentation is loading. Please wait.
1
第二章 C++对C 在非面向对象方面的改进 更简洁,更安全
2
一、注释符 注释的用途: ① 提高可读性 ② 调试程序时屏蔽暂时不用的代码 ③ 生成文档
C:/*……*/ 多行(块)注释分界符号,可出现在空格可出现的任何地方,通常不能嵌套 C++:// …… 单行注释符,到本行末尾结束
3
习惯: ① 为提高通用性,常用英语写注释 ② 注释是为了完善你的代码,而不是重复你的代码,没有额外价值的注释不如不加 ③ 因不同编译器对嵌套注释(调试时,屏蔽一段带注释的代码) 处理不同,有的不支持,故注释不要嵌套
4
二、变量初始化运算符:( ) C:int x=2; C++:int x(2); 例: 非法:int x; x(2);
合法:int x(2),y,z(3);
5
三、新的换行符:endl C:" \n " 转义字符 C++:endl (end of line)
6
四、新的I/O流 C: 库函数:scanf("%d",&x); printf("%d",x); 效率低,不安全。
它们在头文件stdio.h中定义
7
C++:I/O流:cin>>x; cout<<y;
cin:是标准输入流类istream类预定义的对象引用 >>:提取符,是istream类中重载的运算符,可以连用 cout:是标准输出流类ostream类预定义的对象引用 <<:插入符,是ostream类中重载的运算符,可以连用 它们都在头文件"iostream.h"中定义
8
例1: scanf("%d%d%d",&x,&y,&z); //cin>>x>>y>>z; printf("%d%d%d",x,y,z); //cout<<x<<y<<z; 例2: #include "iostream.h" void main( ) {int x=25; cout<<hex<<x<<dec<<x<<oct<<x<<endl; } 结果:192531
9
例3:#include "iostream.h" void main( ) {int x=25; cout<<x<<hex<<x<<x<<endl;//251919 cout<<x<<oct<<x<<x<<endl; //193131 cout<<"x+5 is:"<<x+5<<endl;//x+5 is:36 } 格式: cin>>变量名 cout<<变量名、表达式、字符串常量 应注意运算符的优先级,必要时应加括号
10
五、灵活的局部变量说明 C:局部变量说明必须置于可执行代码段之前
习惯:较短函数中局部变量常集中在函数的开始处说明,较长函数中常在使用处定义局部变量
11
例: # include "iostream.h" void main( ) {int x=1; if(int x=2)x=3; else x=4; cout<<x<<endl; } 结果:1
12
例: #include <iostream.h> void main( ) {int x=1; if(x>0) int x=3; if(x>2)x=5; cout<<x<<endl; } 结果:1
13
例: #include "iostream.h" void main( ) {int x=1; if(x>2) int x=5; else int x=0; cout<<x<<endl; } 结果:1
14
例: #include "iostream.h" void main( ) {int y=1; for(int x=0; x<3; x++) int y=4; cout<<y<<endl; } 结果:1
15
例: #include "iostream.h" void main( ) {int x=5, y=4; switch(int x=y%2) {case 0: case 1:cout<<x<<endl; } cout<<x<<endl; 结果:0,5
16
例: #include "iostream.h" void main( ) {int x=1; if(x>2) int x=5; else x=0; cout<<x<<endl; } 结果:0
17
例: #include "iostream.h" void main( ) {int x=1; if(x>2) x=5; else int x=0; cout<<x<<endl; 结果:1
18
六、结构、联合、枚举名和类名可直接作为类型名
C: 结构名、联合名、枚举名须加上各自的关键字才是类型名 在定义变量时,须在结构名、联合名、枚举名前冠以关键字struct、union、enum C++: 结构名、联合名、枚举名、类名本身就是类型名,在定义变量时,不必在其前加struct、union、enum、class
19
例: enum bool{FALSE ,TRUE}; struct student {char * name; int age; }; C: enum bool b1,b2; struct student s1,s2; C++: bool b1,b2; student s1,s2;
20
七、const修饰符: 只读 符号常量的优点: ① 提高可读性:见名知义 ② 便于修改程序:一改全改 C:
#define LIMIT 60 符号常量,不安全,无参的宏,不占用存储空间
21
C++: const int LIMIT=60; 占内存,只读变量,能进行类型检查,更安全,定义时必须同时初始化 const修饰指针: ① 指向常量的指针:const类型符 * 指针名=值;//指针所指对象被冻结 ② 常指针:类型符 * const 指针名=值; //指针被冻结 ③ 指向常量的常指针:const类型符 * const 指针名=值; //指针及指针所指对象均被冻结
22
例1: ① const char * p="book"; 则:p[3]='t'; (×) p="good"; (√) ② char * const p="book"; 则:p[3]='t'; (√) p="good"; (×) ③ const char * const p="book"; 则:p[3]='t'; (×) p="good"; (×)
23
例2: # define AGE1 18 (√) const int AGE1=18; (√) # define AGE (√) const int AGE2=18.45; (×)
24
const常量作函数的形参: 若在定义函数时,只允许函数体访问(读)形参变量的值,不允许修改(写)它的值,则在形参变量定义的前面加上const 例:void fun(const int & x,const int & y) 则:x++,y++均非法 目的:提高数据的安全性
25
例3: # include "iostream.h" void main( ) {int a=2; # define A a+a # define B A-A // a+a-a+a cout<<3*B<<endl; } //3*a+a-a+a=3* 结果:8
26
# include "iostream.h" void main( ) {int a=2; const int A=a+a; //A=4 const int B=A-A; //B=0 cout<<3*B<<endl; }//3*((a+a)-(a+a))=3*((2+2)-(2+2)) 结果:0
27
例:判断下列程序段的正误 ①int f(const int x) {return x+1;} (√) ②int f(const int x) {return ++x;} (×) ③const int x; x=5; (×)
28
例:判断下列程序段的正误 ①const int x=5; x=x+3; (×) ②const int x=5; const int *p=&x; *p=6; (×) ③int x=5; int * const p=&x; *p=6; (√)
29
④int x=6,y=7; int * const p=&x; p=&y; (×) ⑤const int x=5; const int * const p=&x; * p=10; (×)
30
⑥int x=6,y=7; int * const p=&x; * p=y; (√) ⑦const int x=5; const int y=6; const int * p=&x; p=&y; (√)
31
八、内联函数 C: 宏替换(带参数的宏),无类型检查机制,不安全 C++:
内联函数,编译时用函数的函数体来替代函数调用表达式,能加快代码执行,减少调用开销
32
定义: ① 在普通函数的定义前加inline ② 凡是在类的类体中实现的成员函数都是内联函数 注意: ① 内联函数内不允许有循环语句和开关语句,否则当普通函数处理 ② 内联函数通常适用于短函数 ③ 它是以目标代码的增加为代价来换取运行时间的节省
33
例:# include "iostream.h" # define mul(x) x*x void main( ) {cout<<mul(2+3)<<endl; //2+3*2+3 cout<<mul( )<<endl; // * } 结果:
34
# include "iostream.h" inline int mul(int x) {return x*x;} void main( ) {cout<<mul(2+3)<<endl; //cout<<mul( )<<endl;非法 } 结果:25
35
例:inline int cube (int n)
{return n*n*n;}
36
函数: ① 减少目标代码,实现程序代码和数据的共享,代码复用 ② 让使用者只关心函数的功能和用法,不必关心其实现,减少了用户的负担,屏蔽实现细节 ③ 函数调用浪费时间浪费空间(保护现场,恢复现场),故它是以降低效率为代价的
37
内联函数: ① 用替换代替调用,从而提高效率,用空间换时间 ② 内联函数的定义,必须出现在对其调用之前 ③ 内联函数不能递归调用,其中不能定义静态变量和数组
38
九、函数原型 C: 函数提前声明(先使用后定义),即函数首部(函数头)
39
C++:函数原型 ① 提供函数的函数名及函数返回值类型,以及形式参数的个数、类型和次序 ② 参数表中的参数允许只给类型而省去参数名,在函数原型最后应加分号 ③ 任何函数均应提供函数原型(除先定义,后使用者外) ④ 形参说明必须放在函数名后的括号内,不能放于函数首部与函数体之间
40
例: double f(int x,char y,float z) {return x+y+z;} 则其函数原型为: double f(int x,char y,float z); 或double f(int , char , float);
41
十、带有缺省(默认)参数值的函数 C: int x=2; 变量可带缺省(默认)值
42
C++:允许函数的形参变量带缺省值(默认值)
实质为函数重载的另一种形式,提高了函数调用的灵活性 函数调用时,编译器按从左至右的顺序将实参与形参变量匹配 当实参个数不够时,则采用形参缺省值来补足所缺实参 所有取缺省值的形参都必须出现在不取缺省值的参数的右边 当函数有原型时,形参的缺省值应在函数原型中声明,即缺省参数的说明,必须出现在函数调用之前
43
例: int add(int x=1,int y=2,int z=3) {return x+y+z;} 若int m=add( ); 则m=6 若int n=add(10); 则n=15 若int k=add(10,20); 则k=33 若int i=add(10,20,30); 则i=60 若int j=add( , ,30); 则非法
44
若某缺省参数需指明一个特定值,则在其左边的所有参数都必须赋值
例: int f(int x=1,int y=2,int z); (√) int f(int x,int y=1,int z=2); (×) int f(int x=1,int y,int z=3); (×) int f(int x,int y=2,int z); (×)
45
对形参缺省值的指定可以是任意初始化表达式,甚至可以包含函数的调用
例:# include "iostream.h" int a(8),b(7); void f(int x,int y=a+b,int z=a-b); void main() {f(10); f(20,30); f(40,50,60); } void f(int x,int y,int z) {cout<<x<<y<<z<<endl;} 结果: 10151 20301 405060
46
在相同的作用域内,默认形参值的说明应保持唯一 在不同的作用域内,允许说明不同的默认形参
例:# include "iostream.h" void f(int x=1,int y=2);//全局默认形参值 void g( ){f( );} void main( ) {void f(int x=3,int y=4);//局部默认形参值 f( ); g( ); } void f(int x,int y) {cout<<x<<y<<endl;} 结果: 34 12
47
十一、函数重载 C: 不允许函数同名,不同作用域或生存期的两变量可以同名
48
C++: 在一定条件下允许函数同名,即重载 重载:一个标识符具有两个或两个以上的意义 它在任一特定环境下所表述的意义还必须由其所处的上下文环境来决定 包括函数重载、运算符重载等
49
函数重载:同一个函数名字对应着多个不同的函数实现
当两个或两个以上普通全局函数的形参个数、类型和顺序不完全相同时,它们可以同名 当同一个类的两个或多个成员函数的形参个数、类型和顺序不完全相同时,它们可以同名 同名函数根据参数个数或类型或顺序来区分 普通全局函数与类的成员函数之间可以同名 基类(父类)成员函数和派生类的成员函数之间也可同名 同名函数根据对象名或类名来区分
50
函数重载目的: 同一个函数调用语句可以绑定(联编)于不同的函数体,实现了代码共享 使程序员摆脱词汇(名字空间,命名冲突)的复杂性,增加了程序的可读性 习惯:重载函数应完成相同或相似的功能
51
例: ① int f(int x) {return x+1;} ② double f(double x) {return x+1;} ③ char f(char x) 则: cout<<f(3); //调① cout<<f(3.3); //调② cout<<f('a'); //调③
52
例:① int add( ) {return 0;} ② int add(int x) {return x;} ③ int add(int x,int y) {return x+y;} 则: cout<<add( ); //调① cout<<add(3); //调② cout<<add(3,4); //调③
53
例:下列函数能重载吗? ① int f(int x); int f(int y); (×) ② int f( ); double f(); (×) ③ int f(int x,char y); int f(int y,char x); (×) ④ int f(char x,int y); int f(int y,char x); (√)
54
⑤ int f(int x,int y=1); int f(int x); (×) ⑥ int f(char x,int y=1); int f(int x); (√) ⑦ int f(int x); int f(int & x); (×) ⑧ void f( ); void f( )const; (√)
55
重载函数的选择顺序: 将实参与形参一一比较 ① 先查找参数严格匹配的,若找到,就调用之,否则 ② 再通过自动隐式类型转换查找参数匹配的,若找到就调用之,否则 ③ 最后通过用户定义的强制类型转换查找参数匹配的,若找到就调用之,否则显示函数调用错误
56
例:① void f(int); ② void f(int,int); ③ void f(double); ④ void f(double, double); 则: f(1); // 匹配① f(2.5); // 匹配③ f(2,3); // 匹配② f('A'); // 匹配① f((double)4); //匹配③ f('B','C'); //匹配② f('D',2.5); //匹配④ f(5,2.5); //匹配④ f(); //调用失败,出错 f(1,2,3.5); //调用失败,出错
57
十二、作用域运算符 :: 在内层作用域中,外层作用域中声明的同名标识符是不可见的
十二、作用域运算符 :: 在内层作用域中,外层作用域中声明的同名标识符是不可见的 C:当局部量与全局量同名时,在局部量的作用域内,全局量被屏蔽(隐藏),不可见 C++:可通过作用域运算符改变全局量的可见性
58
例:# include "iostream.h" int x=5; void main() { int x=10; x=20; ::x=30; cout<<x<<::x<<endl; } 结果:20 30
59
例:# include "iostream.h" int s=1; void main() {double s=2.2; { :: s=5; cout<<s<<endl; s=10; } 结果:
60
例:# include "iostream.h" int a=1; void main() {int a=2; {int a=3; ::a=4; } cout<<a<<::a<<endl; 结果: 24
61
例:# include "iostream.h" int a=1; void main() {int a=2; {int a=3; cout<<a<<::a<<endl; } 结果:
62
例:# include "iostream.h" int a=1; void main() {int a=2; { a=3; ::a=4; } cout<<a<<::a<<endl; 结果: 34
63
例:# include "iostream.h" int a=1; void main() {a=2; {int a=3; ::a=4; } cout<<a<<endl; 结果: 4
64
十三、类型转换函数 1.C (1)隐式类型转换: ① 不同类型量混合运算:低→高 ② 赋值语句: 右→左 ③ 函数实参→形参
④ 函数返回值→函数类型 (2)显式类型转换:强制类型转换运算符 (类型符)(表达式) 或(类型符)表达式
65
2.C++ 类型转换函数→目标类型符作函数名,提高了可读性 类型符(表达式)
66
例: ① float i=-2.8; int j=int(i); 则j=-2 i=-2.8 ② float i=2.8; int j=int(i); 则j=2 i=2.8 ③ float i=-1.5; int j=(int)(i); 则j=-1 i=-1.5 结论: 向零取整:取与它最接近的且靠近0那边的那个整数 或截尾:直接去掉小数点后面的所有数据
67
十四、new和delete运算符 C:库函数 malloc( ) 动态分配内存 free( ) 动态释放内存 效率低 C++:运算符
更好,更简单,两运算符均可重载
68
指针名=new 类型符; 从内存堆中分配一块sizeof(类型符)字节大小的内存,其首址存于指针中 delete 指针名; 释放new分配的存储空间 为数组动态分配和释放内存: 指针名=new 类型符[大小][大小]……; delete [ ] 指针名;
69
例:# include "iostream.h" void main() {int * p,* q; p=new int; q=new int(100); *p=10; cout<<*p<<*q<<endl; delete p; delete q; } 结果:10100
70
例:# include "iostream.h" int main() {int * p=new int[10]; if(!p) {cout<<"allocation failure.\n"; return 1; //程序出现异常情况 } p[2]=20; p[3]=30; cout<<p[2]+p[3] <<endl; delete [ ] p; return 0; //程序运行过程中没有出现错误 结果: 50或allocation failure.
71
指针悬挂: 语句p=q; 使p原来指向的空间再也无法访问,且不能被释放,即为无用单元 语句delete p; 还会导致两次释放同一块存储空间
72
例:# include "iostream.h" int main() {int * p=new int(1); int * q=new int(2); cout<<*p<<*q<<endl; //12 p=q; cout<<*p<<*q<<endl; //22 delete p; delete q; } 结果: 12 22 运行时出问题
73
例:# include "iostream.h" void main() {int * p=new int(1); int * q=new int(2); cout<<*p<<*q<<endl; //12 *p=*q; cout<<*p<<*q<<endl; //22 delete p; delete q; } 无指针悬挂
74
例:# include "iostream.h" # include "string.h" void main() {char *p=new char[10]; char *q=new char[10]; strcpy(p,"abcd"); strcpy(q, "efgh"); cout<<p<<q<<endl; //abcdefgh p=q; cout<<p<<q<<endl; //efghefgh delete[]p; delete[]q; } 有指针悬挂问题
75
例:# include "iostream.h" # include "string.h" void main() {char *p=new char[10]; char *q=new char[10]; strcpy(p,"abcd"); strcpy(q, "efgh"); cout<<p<<q<<endl; //abcdefgh strcpy(p,q); cout<<p<<q<<endl; //efghefgh delete[]p; delete[]q; } 无指针悬挂问题
76
例:# include "iostream.h" void main() {int *p=new int(2); int *q;q=p; cout<<*p<<*q<<endl; //22 delete p;p=0; //*q=3; //cout<<*q<<endl; } 指针悬挂引用
77
例:# include "string.h" # include "iostream.h" void main() {char *p=new char[10]; strcpy(p,"abcd"); char *q; q=p; cout<<p<<q<<endl; //abcdabcd delete[]p;p=0; //*q='e'; //cout<<q<<endl; } 指针悬挂访问
78
十五、引用 C:指针 int * p=&a; 通过地址间接访问某个变量,作函数参数时可实现双向传递,不拷贝副本 C++:引用
通过别名直接访问某个变量,它是另一个变量的别名,类似于共用体(联合)
79
引用必须初始化,且一旦初始化后不得再作其他变量的别名
格式:类型符 & 引用名=已定义的同类型变量 主要用作函数的参数或函数的返回值,实现双向传递功能 引用传别名,指针传地址 返回引用的函数,其函数调用可作赋值语句的左值 目的:在函数间传递数据
80
例:# include "iostream.h" void main( ) {int a=3; int & b=a; cout<<a<<b<<endl;//33 b=5; cout<<a<<b<<endl;//55 }
81
例1:# include <iostream.h>
void main() {int x=24; int & y=x; cout<<x<<y<<endl;//24 24 y=46;x=y+3; cout<<x<<y<<endl; //49 49 cout<<&x<<&y<<endl; //同 } //例:0x0065FD4 0x0065FD4
82
例2:# include <iostream.h>
void main() {int a [5]={10,20,30,40,50}; int * p=a; int * & r=p; //r是p的引用,p和r均指向a[0]元素 cout<<*p<<*r<<endl; //*p和*r都表示对象a[0] 1010 p++; r++; cout<<*p<<*r<<endl; //*p和*r表示对象a[2] 3030 }
83
例3:# include "iostream.h" void main( ) {int a=3,*p; int & b=a; p=&b;cout<<b<<*p<<endl; //33 b=10; *p=20; cout<<a<<b<<endl;//2020 }
84
例:# include "iostream.h" void swap(int * m,int &n ) {int t; t=*m;*m=n;n=t; } void main() {int a=5,b=10; swap(&a,b); cout<<a<<b<<endl; //105
85
例: # include <iostream.h>
int a[ ]={1,3,5,7,9}; int & f(int i) {return a[i]; } void main( ) {f(2)=10; cout<<a[2]<<f(2)<<endl;//1010 }
86
例:# include <iostream.h>
int & max(int & x,int & y) {return (x>y)?x:y;} void main( ) {int a=5,b=10; max(a,b)=20; cout<<a<<b<<endl;//520 }
87
例:# include <iostream.h>
int & f(int & m) {m+=1; return m;} void main( ) {int k=10; int &n=f(k); cout<<k<<endl; //11 n=20; cout<<k<<endl; //20 }
88
例:# include <iostream.h>
int & g(int * p) { return *p;} void main( ) {int a=10; cout<<g(&a)+10<<endl; //20 g(&a)=100; cout<<a<<endl; //100 }
89
例:# include <iostream.h>
int & f( ) {static int i=1; return ++i;} int g() {int j=1; return ++j;} void main( ) {int & a=f(); int b=g(); cout<<a<<b<<endl; //22 a=10; b=10; a=f(); b=g(); cout<<a<<b<<endl; //112 }
90
例:# include "iostream.h" void main( ) {int a=100; int & b=a; cout<<b<<endl; //100 b=b-80; cout<<a<<endl; //20 a=a+30; cout<<b<<endl; //50 }
91
在定义返回引用的函数时,不能返回该函数内的局部变量
原因:当函数返回时,局部变量自动消失(生存期结束,自动释放内存) 例:① int f( ) {int x=5; return x; } //(√) ② int & f( ) {int x=5; return x; } //(×) ③ int & f(int x) {return x;} //(×)
92
④ int * f(int & x) {return & x;} //(√) ⑤ int & f(int & x) {return x;} //(√) ⑥ int & f(int * p) {return * p;} //(√) ⑦ int f(int & x) ⑧ int & f( ) {static int x=5; return x; } //(√)
93
例:# include "iostream.h" void f(int a,int & b) {a=a+10; b=b+10; cout<<a<<b<<endl;//1215 } void main( ) {int x=2,y=5; f(x,y); cout<<x<<y<<endl;//215
94
例:# include "iostream.h" void main( ) {int a=1; int & b=a; int c=2; b=c; cout<<a<<b<<endl;//22 c=3; }
95
例:# include "iostream.h" void main() {int a=1; int &b=a; int c=2; b=c; b=3; cout<<a<<b<<c<<endl; //332 }
96
例:# include "iostream.h" void main() {int * a; int * & p=a; int b=80; p=&b; cout<<*a <<endl; //80 }
97
例:# include "iostream.h" void main( ) {int a=5; int * p=&a; int *&q=p; *q=10; cout<<a<<endl;//10 }
98
例:# include "iostream.h" void main( ) {int a=5; int & b=a; int & c=b; c=10; cout<<a<<endl;//10 }
99
例:# include "iostream.h"// VC++上无法通过
void main( ) {const int a=5; int & b=a; //当引用的初值是一常量或常变量时,系统将先生成一个临时变量,再赋给引用名,即引用是临时变量的别名 cout<< b<<endl;//5 b=b+20; cout<<a<<b<<endl;//5 25 }
100
例:# include "iostream.h" //VC++上无法通过
void main() {const int a=5; int &b=a; int &c=b; ++b; cout<<a<<b<<c<<endl; //566 ++c; cout<<a<<b<<c<<endl; //588 }
101
十六、无名联合 即没有名字的联合,可直接使用其成员名
102
例:# include "iostream.h" static union {int x; int y; }; void main() {x=3; y=4; cout<<x<<y<<endl; } 结果:44
103
例: # include "iostream.h" void main() {union {int a; int b; }; a=5; b=7; cout<<a<<b<<endl; //77 a=10; cout<<a<<b<<endl; //1010 }
104
例:# include <iostream.h>
void main() {union {int x; int y; }; x=5; y=7; int & z=x; cout<<x<<y<<z<<endl; } 结果:777
105
例:# include <iostream.h>
void main() {union{int x; int y; }; int & z=x; z=9; cout<<x<<y<<z<<endl; } 结果:999
Similar presentations