1、第2章 C+对C的扩充,第2章 C+对C的扩充,2.1 C+的特点 2.2 C+语言的文件扩展名 2.3 注释符 2.4 名字空间 2.5 C+语言的输入输出 2.6 变量的定义 2.7 强制类型转换,2.8 动态内存的分配与释放 2.9 作用域运算符: 2.10 引用 2.11 const修饰符 2.12 字符串 2.13 C+语言中函数的新特性 习题,OK,2.1 C+的特点 C+语言既保留了C语言的有效性、灵活性、便于移植等全部精华和特点,又添加了面向对象编程的支持,具有强大的编程功能,可方便地构造出模拟现实问题的实体和操作;编写出的程序具有结构清晰、易于扩充等优良特性,适合于各种应用软
2、件、系统软件的程序设计。用C+编写的程序可读性好,生成的代码质量高,运行效率仅比汇编语言慢10%20%。,2.2 C+语言的文件扩展名,(1)规定用“.cpp”(意即C Plus-Plus)作为C+语言源文件的扩展名,“cpp”的文件扩展名与操作系统无关。 (2)与C+语言源文件相关的头文件扩展名一般仍用“.h”,但有些操作系统也有规定使用“.hpp”充当头文件扩展名的。,2.3 注释符,1. 段注释: /*/ 2. 单行注释:/ 当只做单行注释时便可用“/”符号表示从此符号起至行尾均为行注释内容。3. 程序编译时将忽略所有的注释内容。,2.4 名字空间(名空间namespace),名字空间域
3、是随标准C+而引入的。它相当于一个更加灵活的文件域(全局域),可以用花括号把文件的一部分括起来,并以关键字namespace开头给它起一个名字: namespace ns1 float a,b,c;fun1() ,Note: (1)声明块中可以包括:类、变量(带有初始化)、函数(带有定义)等。 (2)在域外使用域内的成员时,需加上名字空间名作为前缀,后面加上域操作符“:” 。如:ns1:a,ns1:fun1()等等。 (3)这里添加了名字空间名称的成员名被称为限定修饰名。 (4)最外层的名字空间域称为全局名字空间域(global namespace scope),即文件域。,(5)名字空间域可
4、分层嵌套,同样有分层屏蔽作用。例如: namespace n1namespace n2 / 名字空间嵌套class matrix / 名字空间类成员matrix 访问matrix,可写:n1:n2:matrix 。,(6)使用using声明可只写一次限定修饰名。using声明以关键字using开头,后面是被限定修饰的(qualified)名字空间成员名,例如: using n1:n2:matrix; / 名字空间类成员matrix的using声明 以后在程序中使用matrix时,就可以直接使用成员名,而不必使用限定修饰名。,(7) 使用using指示符可以一次性地使名字空间中所有成员都可以直接
5、被使用,比using声明方便。using指示符以关键字using开头,后面是关键字namespace,然后是名字空间名。,(8)标准C+库中的所有组件都是在一个被称为std的名字空间中声明和定义的。在采用标准C+的平台上使用标准C+库中的组件,只要写一个using指示符:using namespace std;就可以直接使用标准C+库中的所有成员。注意:如果使用了名空间std,则在使用#include编译预处理命令包含头文件时,必须去掉头文件的扩展名.h,否则会出错。,2.5 C+语言的输入输出,C+语言另外定义了一套保留字与运算符来替代C语言中对标准输入、输出函数的引用。C+语言的保留字为:
6、 cout“输入内容”; / cin为标准输入流对象(默认从键盘输入) #include ,【例2.1】C+的输入输出举例。 #include / 使用名空间std,则必须去掉.h扩展名 using namespace std; void main() char name10;int age;coutname;coutage;cout“name is “nameendl;cout“age is “ageendl; ,2.6 变量的定义,(1)一是允许变量的定义语句可以出现在程序的任何位置,使得局部变量的定义点与使用点不至于离得太远,增强程序的可读性,而且也不必在编写某一程序块的开始时就考虑要用
7、到哪些变量; (2)二是允许直接使用结构体名定义变量,这种扩展为程序员在编程中提供了不少方便。类似地在C+语言中联合名、枚举名也可在定义后独立地作为类型名使用。,【例2.2】C+的变量定义举例。 #include using namespace std; void main() struct studentint no;float math; ;int n;cinn;student wang; wang.no=n;cinwang.math;coutwang.no“ “wang.mathendl; ,2.7 强制类型转换,格式: (数据类型) (表达式) 数据类型 (表达式),2.8 动态内存的
8、分配与释放,1.new运算符指针变量 = new 数据类型;new从堆内存中为程序分配可以保存某种类型数据的一块内存空间,并返回指向该内存的首地址,该地址存放于指针变量中。,2.delete运算符 运算符delete用于释放new分配的内存空间,它的使用形式为: delete 指针变量; 其中的指针变量保存着new动态分配的内存的首地址。 3. 注意: (1) 用new获取的内存空间,必须用delete进行释放; (2) 对一个指针只能调用一次delete; (3) 用delete运算符作用的对象必须是用new分配的内存空间的首地址。,#include using namespace std;
9、 void main() int *p; p=new int; / 分配内存空间 *p=5; cout*p; delete p; / 释放内存空间,【例2.3】new与delete应用举例。,在用new分配内存的同时进行初始化。使用形式为: 指针变量 = new 数据类型(初始值); 例如上例中的: p=new int; *p=5; 也可写成: p=new int(5);,4用new建立数组类型的变量,语法:指针变量= new 数据类型数组大小; delete 指针变量; 多维数组:指针变量= new 数据类型数组大小可用变量固定大小; delete 指针变量;/delete 指针变量; 例如
10、:略(板书),4用new建立数组类型的变量,注意在使用delete时,不用考虑数组的维数。 当不能成功地分配到所需要的内存时,new返回0,即空指针。例如:int *p= new int100; if(p=0) cout “cant allocate more memory,terminating. “endl; exit(1); 其中exit函数的作用是终止程序运行。,#include using namespace std; void main() int n; / 定义数组元素的个数int *p; coutn;,【例2.4】从堆内存中获取一个整型数组,赋值后并打印出来。,if(p=new
11、 intn)=0) cout “cant allocate more memory,terminating. “endl; exit(1); / 分配内存空间for( int i=0;in;i+) pi= i *2;cout“Now output the array : “endl;for( i=0;in;i+)coutpi “ “;coutendl;delete p; / 释放内存空间 ,2.9 作用域运算符:,通常情况下,如果全局变量与局部变量同名,那么局部变量在其作用域内具有较高的优先权。C语言规定只能在变量的作用域内使用该变量,不能使用其他作用域中的变量,可采用C+中提供的作用域运算符
12、:,它能指定所需要的作用域。注意:不能用:访问函数中的局部变量。在C+语言中作用域运算符:还用来限定类的成员,,#include using namespace std; float a=2.4; / 全局变量 void main() int a=8; / 局部变量 coutaendl; cout:aendl; / :a表示全局作用域中的变量a ,2.10 引用,(1)引用是C+语言的一个特殊的数据类型描述,用于在程序的不同部分使用两个以上的变量名指向同一地址,使得对其中任一个变量的操作实际上都是对同一地址单元进行的。 (2)在这种两个以上变量名的关系上,被声明为引用类型的变量名则是实际变量名
13、的别名。 引用运算符为&,声明引用的一般形式为: 数据类型 &引用变量名 = 变量名; 或 数据类型& 引用变量名 = 变量名; 或 数据类型 & 引用变量名 = 变量名;,2.10 引用,(3)对引用进行操作,实际上就是对被引用的变量进行操作。 (4)引用不是值,不占存储空间,声明引用时,目标的存储状态不会改变。引用一旦被初始化,就不能再重新赋值。,【例2.5】引用举例。 #include void main() int num=50; int ,说明: (1) 在一行上声明多个引用型变量(函数)名时,要在每个变量(函数)名前都冠以“是允许的。,(4) 由于引用不是变量,所以,不能说明引用的
14、引用,也不能说明数组元素的类型为引用数组,或指向引用的指针。例如: int / a指向变量b (5) 引用与指针不同。指针的内容或值是某一变量的内存单元地址,而引用则与初始化它的变量具有相同的内存单元地址。指针是个变量,可以把它再赋值成其它的地址,然而,建立引用时必须进行初始化并且决不会再指向其它不同的变量。,(6) 要注意区分引用运算符和地址运算符的区别。例如: int num=50; int / num被修改为100 其中ref2也是对num的引用。,(8) 可以把函数的参数说明成引用以建立函数参数的引用传递方式。 例2.7数值交换(引用作为函数参数)举例。 #include using
15、namespace std; void swap(int ,(9) 有空指针,无空引用 (10) 引用不能用数据类型来初始化。如:int &ref=int; / error (11) 函数调用可以作为左值引用表达式是一个左值表达式,因此它可以出现在形、实参数的任何一方。若一个函数返回了引用,那么该函数的调用也可以被赋值。一般说,当返回值不是本函数内定义的局部变量时就可以返回一个引用。在通常情况下,引用返回值只用在需对函数的调用重新赋值的场合,也就是对函数的返回值重新赋值的时候。避免将局部作用域中变量的地址返回,就使函数调用表达式作为左值来使用。 【例2.8】统计学生中A类学生与B类学生各为多少
16、个。A类学生的标准是平均分在80分以上,其余都是B类学生。 【例2.9】返回的局部作用域内的变量,函数作为左值。,如何:改掉警告错误? 补充:数组的引用(P25),2.11 const修饰符,#define PI 3.1415926 const float PI=3.1415926; 这个常量是有类型的,它有地址,可以用指针指向这个值,但不能修改它。C+建议用const取代#define定义常量。,注意:,(1) 使用const修饰符定义常量时,必须初始化; (2) 常量一旦被定义,在程序中任何地方都不能 再更改。 (3) 如果用const定义的是一个整型常量,int可以省略。 (4) 与#d
17、efine定义的常量有所不同,const定义的常量可以有自己的数据类型,这样C+编译程序可以进行更加严格的类型检查,具有良好的编译时的检测性。,(5) 函数参数也可以用const说明,用于保证实参在该函数内部不被改动,大多数C+编译器能对具有const参数的函数进行更好的代码优化。例如,通过函数max求出整型数组a100中的最大值,函数原型应该是:int max(const int*pa);这样做的目的是确保原数组的数据不被破坏,即在函数中对数组元素的操作只许读,不许写。,const与指针一起使用的组合情况:,(1) 指向常量的指针指向常量的指针是指一个指向常量的指针变量。const char
18、 *pc=“abcd“; 声明指向常量的指针变量pc,它指向一个字符串常量,由于使用了const,不允许改变指针所指的常量,因此以下语句是错误的: pc3=x; 但是由于pc是一个指向常量的普通指针变量,不是常指针,因此可以改变pc的值。例如以下语句是允许的:pc=“jkkk“;,const与指针一起使用的组合情况:,(2) 常指针 常指针是指指针本身,而不是它指向的对象声明为常量。例如: char* const pc=“abcd”; / 常指针 pc3=x; / 合法 pc=“dfasdfa“; / 不合法,const与指针一起使用的组合情况:,(3) 指向常量的常指针 整个指针本身不能改变
19、,它所指向的值也不能改变。要声明一个指向常量的常指针,二者都要声明为const。例如: const char* const pc=“abcd”; / 指向常量的常指针 pc3=x; / 错误,不能改变指针所指的值 pc=“dfasdfa“; / 错误,不能改变指针本身,2.12 字符串,在C+中提供了一种既方便又好用的string类型。下面通过一个简单的例子说明string类型的使用。 【例2.10】字符串类string的使用。,2.13 C+语言中函数的新特性,2.13.1 函数原型(Function Prototype) 2.13.2 内联(inline)函数 2.13.3 带缺省参数的函
20、数 2.13.4 函数重载(overload) 2.13.5 函数模板(function template),C+要求为每一个函数建立原型,用以说明函数的名称、参数个数及类型和函数返回值的类型。 其主要目的是让C+编译程序进行类型检查,即形参与实参的类型匹配检查,以及返回值是否与原型相符,以维护程序的正确性。所以应养成将声明与定义分别编写的编程习惯。 函数原型与函数的定义要在函数的返回类型,函数名和参数的类型及数量这三条线上保持一致。 当然,在写函数原型时,可以省略形参的名字,因为参数名对编译器没有意义,但如果取名恰当的话,这些名字可以起到提示参数用途的作用。,2.13.1 函数原型(Func
21、tion Prototype),2.13.2 内联(inline)函数,使用内联函数是一种用空间换时间的措施,若内联函数较长,且调用太频繁时,程序将加长很多。因此,通常只有较短的函数才定义为内联函数,对于较长的函数最好作为一般函数处理。,2.13.2 内联(inline)函数,一般情况下,我们对内联函数做如下的限制: (1) 不能有递归 (2) 不能包含静态数据 (3) 不能包含循环 (4) 不能包含switch和goto语句 (5) 不能包含数组若一个内联函数定义不满足以上限制,则编译系统把它当作普通函数对待。 【例2.11】内联函数的使用。,2.13.3 带缺省参数的函数,如果在函数说明或
22、函数定义中为形参指定一个缺省值,则称此函数为带缺省参数的函数。当函数调用发生后,在形参表中等号后的各“缺省值”将起实参的传递作用。 如果函数有多个缺省参数,则缺省参数必须是从右向左定义,并且在一个缺省参数的右边不能有未指定缺省值的参数。 void fun(int a=3,int b=6,int c,int d); void fun(int a=65,int b=3,int c,int d=3); ,2.13.3 带缺省参数的函数,需要特别注意的是如果在函数原型的声明中设置了函数参数的缺省值,则不可再在函数定义的头部重复设置,否则编译时将出现错误信息。(思考:如果函数原型中无缺省值,定义时有,正
23、确吗?),2.13.4 函数重载(overload),C+编译系统允许为两个或两个以上的函数取相同的函数名,但是形参的个数或者形参的类型不应相同,编译系统会根据实参和形参的类型及个数的最佳匹配,自动确定调用哪一个函数,这就是所谓的函数重载。函数重载无需特别声明,只要所定义的函数与已经定义的同名函数形参形式不完全相同,C+编译器就认为是函数的重载。【例2.12】重载函数应用举例,在使用重载函数时要注意:, 不可以定义两个具有相同名称、相同参数类型和相同参数个数,只是函数返回值不同的函数。 int func(int x); float func(int x); 如果某个函数参数有缺省值,必须保证其
24、参数缺省后调用形式不与其它函数混淆。 int f(int a, float b); void f(int a, float b, int c=0); 函数调用语句: f(10, 2.0); 具有二义性,既可以调用第一个函数,也可以调用第二个函数,编译器不能根据参数的形式确定到底调用哪一个。,2.13.5 函数模板(function template),C+语言中可以使用模板来避免在程序中多次书写相同的代码。所谓模板是一种使用无类型参数来产生一系列函数或类的机制,是C+的一个重要特征。它的实现方法方便了更大规模的软件开发。模板是以一种完全通用的方法来设计函数和类,而不必预先说明将被使用的每个对象
25、的数据类型。通过模板可以产生类或函数的集合,使它们操作不同的数据类型,从而避免为每一种数据类型产生一个单独的类或函数。 模板分为函数模板和类模板,C+提供的函数模板可以定义一个对任何类型变量进行操作的函数,从而大大增强了函数设计的通用性。这是因为普通函数只能传递变量参数,而函数模板提供了传递类型的机制。使用函数模板的方法是先说明函数模板,然后实例化成相应的模板函数进行调用执行。,1.函数模板,函数模板的一般说明形式如下: template(模板函数形参表) / 函数定义体 模板类型参数(template type parameter)代表一种类型,由关键字 class 或 typename后加
26、一个标识符构成,在这里两个关键字的意义相同,它们表示后面的参数名代表一个基本数据类型或用户定义的类型。,如果类型形参多于一个,则每个类型形参都要使用class或typename。中的参数必须是唯一的,而且中至少出现一次。如:template template函数模板定义不是一个实实在在的函数,该定义只是对函数的描述,表示它每次能单独处理在类型形式参数表中说明的数据类型。 【例2.13】编写一个对具有n个元素的数组a求最小值的程序,将求最小值的函数设计成函数模板。,2.模板函数,函数模板只是说明,不能直接执行,需要实例化为模板函数后才能执行。当编译系统发现有一个函数调用: ; 时,将根据中的类型
27、生成一个重载函数,即模板函数。 模板函数有一个特点,虽然模板参数T可以实例化成各种类型,但是采用模板参数T的各参数之间必须保持完全一致的类型。模板类型并不具有隐式的类型转换,例如在int与char之间、float与int之间、float与double之间等的隐式类型转换。 函数模板方法克服了宏定义不能进行参数类型检查的弊端;克服了C+函数重载用相同函数名字重写几个函数的烦琐。,3.函数模板与重载函数,当模板函数与重载函数同时出现在一个程序体内时,C+编译器的求解次序是先调用重载函数;如果不匹配,则调用模板函数;如果还不匹配则进行强制类型转换,前面几种方法都不对,则最后报告出错。 【例2.14】模板函数与重载函数。,习 题,1分析下列程序的执行结果: 2. 分析下列程序的执行结果: 3. C+语言对C语言在结构化程序设计方面进行了哪些扩充? 4. 下述C+程序有若干处错误,试找出并纠正之。 5. 引用类型与指针类型有什么区别?。 6函数、内联函数以及宏的区别。 7. 函数重载有什么好处? 8. 模板有什么作用?函数模板和模板函数有什么区别?,