程序设计首都师范大学chapter_第1页
程序设计首都师范大学chapter_第2页
程序设计首都师范大学chapter_第3页
程序设计首都师范大学chapter_第4页
程序设计首都师范大学chapter_第5页
已阅读5页,还剩95页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、2.1 C+ 的2.1.2C 语言是1972 年由贝尔和特点的 Dennis Richie 创建的结构化、模块化的面向过程的程序设计语言。C 语言的优点: 功能强、性能好, 高效、灵活, 支持结构化程序设计。C 语言也一些缺点和局限: 类型检查机制相对较弱, 几乎没有支持代码重用的的语言机制和结构, 不适合开发大型程序。随着软件的规模和复杂程度不断增大,软件设计设计和开发的也日益显著。20 世纪 80 年代提出的面向对象的程序设计思想和随后形成的面向对象的程序设计范型使软件工作者看到了从根本上解决软件设计开发的希望;同期望设计出能支持面向对象程序设计范型的新语言。Bjarne Stroustr

2、up 博士和他在贝尔的同事们为了弥补 C 的上述不足和增加面向对象的支持机制,在1980 年设计出了与原来的 C 语言完全兼容,又完全支持面向对象程序设计的新语言(C 语言的扩展增强版),并为该语言赋予了非常贴切相比 C+名 C+。与 C 继承了 C 的原有精髓 高效、灵活; 增加了面向对象的机制,支持大型软件开发; 支持代码重用;正如 Bjarne Stroustrup 对 C+ 的准确表述:What is C+?C+ is a general purpose programming language with a bias towards systems programming that-

3、 is a better C,- supports data abstraction,- supports object-oriented programming,and- supports generic programming.2.2 C+ 源程序的2.2.1 程序的一般格式C+ 是C 的一个超集,所以它几乎保留了 C 的所有特性。例如,一个简单的 C+ 程序如下所示: #include<iostream.h>int main()int x, y, sum;cout << “Enter two numbers:n ” ; cin >> x >>

4、; y;sum = x + y;cout << “The sum is: “ << sum << n; return 0;/ 显示输入提示/ 输入整型数值/ 输出计算结果与该程序具有相同功能和输出结果的 C 程序如下:#include<stdio.h> main()int x, y, sum;printf(“Enter two numbers:n”) ; scanf(“%i %i”, &x , &y);sum = x + y;printf(“The sum is: %i n”, sum);/* 显示输入提示 */* 输入整型数值

5、*/* 输出计算结果 */比较两个程序,比较不难发现,二者在格式、语法结构方面保持着一致性,但也着一些不同之处: C+ 标准要求 main 函数必须为 int 类型,并在程序正常执行结束时向系统返回数值0,否则返回数值 -1。但目前并非所有的 C+ 编译系统都严格实行了这一标准,因此在大多数 C+ 编译系统中仍可以将 main 函数必须为 void 类型(但不提倡)。注意,如果 main 函数未加任何类型int 类型。,则缺省为 C+ 标准使用 /* */ 和 / 两种注释语法。 C+ 程序一般使用 输出流对象 cout 进行输出,但也使用函数 printf 进行输出。 C+ 程序一般使用 输

6、入流对象 cin 进行输出,但也使用函数 scanf 进行输入。 输出流对象 cout 和 输入流对象 cin 的在头文件iostream.h 中,因此必须在 main 函数之前添加预处理命令 #include “iostream.h”。如果要在 C+使用 printf 和 scanf 则必须在 main 函数之前添加预处理命令 #include “stdio.h”。注意,输出流对象 cout 和 输入流对象 cin 还被定义在 C+ 的标准库中,C+ 标准库的头文件名均没有扩展名“.h”,并且库中声明在命名空间 “std” 中。因此,如果在C+ 标准库,则上述 C+ 程序应改写如下:C+ 的

7、类和、函数、对象都使用#include<iostream> using namespace std; int main()int x, y, sum;cout << “Enter two numbers:n ” ; cin >> x >> y;sum = x + y;cout << “The sum is: “ << sum << n; return 0;/ 显示输入提示/ 输入整型数值/ 输出计算结果Java 程序在形式上与 C+ 程序很相似,在 Java 程序中函数的定义格式与 C+ 相同,也必须有一个,并

8、且只有一个 main 函数。但是必须注意,Java 程序中的 main 函数不像 C+的 main 函数是一个特定的全程函数,而必须是一个类的特定静态成员函数。2.3 C+ 在混合编程方面的一些特性这些特性是在C 子集的基础上增加的部分,它们既可以用于面向对象编程,也可以用于非面向对象编程。2.3.1注释行C+ 中不但保留了 C 的 /* 和 */ 格式,还增加了/ 格式。例如下面两条语句的注释:x = y + 2; /* This is a comment */和x = y + 2; / This is a comment是等价的。说明: 以 / 开始的注释内容只在本行起作用。显然,当注释内

9、容为多行时使用 / 会不方便,而使用 /* 和*/ 更为适宜。 /* */ 格式的注释不能嵌套,但它可以嵌套 / 方式的注释,例如:/* This is a multi-line comment.Inside of which / is nested a single line comment.Here is the end of the multi-line comment. */2.3.2 面向对象的I/O 操作在误:进行I/O 操作时容易出现如下的运行错Cint i; float f;scanf("%f", &i);printf("%d",

10、 f);这类错误发生的是 scanf 和 printf 中的格式符和所的数据类型不一致,但 C 编译器无法检查这些错误。这证明了操作与数据相关联的重要性。在 C+int i; float f; cin >> i;cout << f;,上述同样的操作可以写成:这是因为在 C+ 中输入运算符 >> 和输出运算符 <<是通过面向对象的重载机制定义在相应的数据类型上的,这就这两个运算符所完成的操作总能正确地施加在它们可以操作的数据上。如果所操作的数据类型是这两个运算符的操作所不的(没有对这些数据类型重载定义这两个运算符的操作),则 C+ 编译器就可以发现

11、。因此从根本上避免了上述 C所发生的运行错误。1 输入流cin>> C+ VariableKeyboard or other inputcin 是标准输入流的对象,代表输入,如键盘。运算符 >> 的功能:取决于该运算符操作数的类型。 当 >> 的两个操作数为 int 类型时,>> 的操作保持C的“右移“运算功能; 当 >> 的左操作数为标准输入流类型时,>> 的操作是从左操作数中数值传送到右操作数中。 除了可以用运算符 >> 进行输入外,还可以使用cin 的成员函数 get 和 getline 完成某些输入。下

12、面通过三个实例来说明如何使用它们以及它们所 完成的操作有什麽不同。在程序之前,先简单一下 Visual C+ IDE 集成编程环境和如何使用该环境进行编程:· 进入 Visual C+ IDE;· 创建一个 Win32 Console Application 项目;· 向一个已经创建的项目中加入源文件;· 编译、调试、执行一个应用程序;· 保存和打开一个已经创建的应用程序项目。例2-1 使用输入运算符 >> 输入五个单独的字符分析: 使用 >> 进行输入操作时,空格/Tab键/两个相邻数据输入的间隔符,其中次输入过程的结

13、束。被作为还被作为一 如果需要输入空格符时,则不能使用 >>,而必须使用 cin 的成员函数 get。注意,调用该函数时必须在 get 之前加上 cin. 例如:char name81;cin.get(name, 80);/ 输入一个带有空格的名字字串get 是以符并不结束一次输入的,get 所获得的输入字符“n”,但并不从输入缓冲区中删除它。因此需要再次调用 get 来删除“n” ,例如:char name81;cin.get(name, 80);cin.get();/ 输入一个带有空格的名字字串/ 删除输入缓冲区中的符get 有多个重载版本,根据参数的不同,相应的 get版本被

14、调用,完成不同的输入操作。从以上的分析不难归纳出如下结论:· 输入数值或不包含空格的字符串时,使用标准输入运 算符 >> 更为方便和安全。· 输入包含空格的字符串时,必须使用成员函数 get 。例2-2 使用成员函数 get 接收字符串分析: 在此如果使用 >>,则空格作为间隔符,因此只能输入姓名字串中空格之前的部分,例如,William Smitch 中的 William 。 如果使用 get,空格被做为有效输入字符,所以可以输入完整姓名字串,例如,William Smitch。如果在输入过程中遇到结束符“”或用户输入的字串长度超过限定长度时,则输

15、入操作结束,字串的剩余部分()被存留在输入缓冲区中。这就产生了一个问题:如果会有什麽问题出现呢?连续使用两次 get 将例2-3 连续使用两次 get 函数产生的问题解决此问题,可以增加一次 get 的调用,用于取走输入缓冲区中残留的,也可以使用 cin 的另一个成员函数getline,该函数能从输入缓冲区中自动删除作为输入结束的。例2-4 使用 getline 改写例2-3几点注意:· 接收输入信息的变量类型可以是除 void 以外的任何预定义类型。·用户在表中连续使用输入运算符 >> 为多个变量输入数据,例如:cin >> a >>

16、b >> c;cin 按输入变量的书写顺序从输入(键盘)上提取所需要的数据,并存入对应的变量。两数据之间用间隔符(空格、输入过程中抛弃间隔符。或Tab键)分隔,并在· 对于自定义类型(结构、类)变量(对象)必须 重载定义输入操作符 >> 对自定义类型变量的操作,才能使用输入操作符 >> 进行输入操作。· 对于输入包含分隔符的字符串必须使用 cin 的成员函数 :get(char* cp, int len, char terminator = n)该函数不自动删除字串结束符“或使用 cin 的另一成员函数:” 。getline(char*

17、pch, int nCount, char delim = n )该函数将自动抛弃字符串结束符“” 。2 输出流coutScreen or other outputdevice<< C+ datacout 是标准输出流的对象,代表输出器屏幕。,如显示运算符 << 的功能:取决于该运算符操作数的类型。 当 << 的两个操作数为 int 类型时,<< 的操作保持的“左移“运算功能;C 当 << 的左操作数为标准输出流类型时, << 的功能是将右操作数(变量)中存放的信息写入左 操作数(标准输出流对象 cout )中。几点注意:

18、· 输出数据可以是除 void 以外的任何预定义类型。·用户在表中连续使用标准输出运算符向标准输出流对象输出多个变量中的信息,例如:cout << a << b << c;按书写顺序将所有右操作数据依次象中。到输出流对· 对于自定义类型(结构、类)变量(实例)必须重 载定义输出操作符 << 对自定义类型变量的操作,才能使用输出操作符 << 进行输出操作。3 输入输出的格式格式是输入输出操作的重要功能。在 C+ 的标准输入输出流中,格式功能是通过流类的成员函数提供。关于这些功能的实现在第八章中叙述,本章只给

19、出一些用于格式的常用算子(特殊函数),以便在初学 C+ 编程中使用。其中 setiosflags 和 resetiosflags 的参数 f 的常用格式标志取值如下表所示:算子含义dec hex oct ws endl ends flushsetiosflags (long f)resetiosflags (long f) setfill (int c) setprecision (int n) setw (int n)设置 I/O 转换基数为10 进制,可用于输入和输出。设置 I/O 转换基数为16 进制,可用于输入和输出。设置 I/O 转换基数为 8 进制,可用于输入和输出。用于在输入时跳

20、过开头的空白符,仅用于输入。一新行( 换行)并刷新流,仅用于输出。一个 NULL 字符,仅用于输出。刷新输出流。设置 I/O 的格式为 f 说明的格式。 清除 I/O 的格式中由 f 说明的格式。设置输出格式中的充填字符。设置输出格式中的浮点数精度为 n 。设置输出格式中的为 n 。格式标志名含义ios:left ios:right ios:scientific ios:fixed ios:dec ios:hex ios:oct ios:uppercase ios:showbaseios:showpos ios:showpoint数据按左对齐输出。数据按右对齐输出。使用科学计数法表示浮点数。使

21、用定点形式表示浮点数。 转换基数为十进制形式。转换基数为十六进制形式。转换基数为八进制形式。十六进制形式和科学计数法输出数值中的字符大写在数字之前输出带有一个表示当前转换基数制式的字符(如 x 表示十六进制, 0 表示八进制)。在正数前添加一个“+”号(否则“+”号是被隐蔽的)。浮点整数输出时带有小数点,并在尾部补0满足当前的浮点精度设置。例2-5 如何在数值的输出中使用不同的转换数制基。系统的缺省基数为10。一种转换基数一旦设置,其效果将保持到程序结束或用户使用另一个基数转换算子。例2-6 在输出中使用不同的。·算子的效果只对一次输出起作用。· 缺省的对齐右对齐。

22、3; 缺省填充字符为空格,而使用改变填充字符。算子 setfill 可以例2-7 在输出中使用左对齐。使用 setiosflags 和标志值 ios:dec、ios:hex 和 ios:oct设置数据的转换数制基和使用算子的效果相同。例如,下面的两条语句的执行结果是相同的:cout << setiosflags(ios:hex) << 44;cout << hex<< 44;如果使用位操作符“|”式,setiosflags可以一次多个格标志,使格式操作更为方便。例如:cout<<setw(10)<<setiosflags(

23、ios:hex|ios:left)<<44<<45;/ 16进制、左对齐输出数字44和45,每个显示cout<<setiosflags(ios:hex|ios:uppercase)<<44;/ 16进制、大写输出10进制数值 44 为“2C” 。为10。resetiosflags 用来取消由参数指定的格式例如,在语句:。cout << setiosflags(ios:hex|ios:uppercase) << 44;执行后,希望保留 16 进制格式,而取消大写格式控制。就可以用如下输出语句实现:cout <<

24、resetiosflags(ios:uppercase) << 44;例2-8 在输出中使用带有基数前缀的显示例2-9 在正数输出中使用“+”符号标记例2-10 在数值输出使用精度·算子 setprecision(i) 将浮点数 1.234567 的输出精度位数逐次设置为 1 到 7 位。· 使用算子 setiosflags(ios:fixed) 的作用是用定点格式显示浮点数,使 setprecision(i) 说明的精度位数是浮点数的小数部分;并且当指定的精度位数多于所输出浮点数的小数有效位时,在有效位后添加有利于格式对齐。0,算子endl 的功能是输出一个“

25、n输出,并且执行算子 flush 刷新输出缓冲区。显然,下面的三条语句具有相同的显示结果。cout << "Hello theren" << flush;cout << "Hello there" << "n" << flush; cout << "Hello there" << endl;算子 ends 是输出一个 NULL 字符。在很多情况下都需要一个零结尾的字符串。例如:cout << 'a' &l

26、t;< 'b' << 'c' << ends;ends 输出到显示器屏幕上时,只是增加一个空白。注意:1 使用 cin 和 cout 进行 I/O 操作时,必须包含(#include)流类库头文件 iostream.h;如果需要使用 I/O 格式,则必须包含头文件iomanip.h,否则将发生编译错误。由于 iomanip.h中已经包含了 iostream.h,所以,iomanip.h,就不必再包含 iostream.h 了。包含了注意,如果通过 C+ 的标准库使用 cin 和 cout 进行 I/O 操作,则程序要包含的库头文件应

27、替换为iostream 和 iomanip(但 iomanip 与 iostream 之间不包含),并且添加使用 C+ 的标准库名字空间的语句: “using namespace std;”。例如:#include <iostream.h>被替换为:#include <iostream>using namespace std;#include <iomanip.h>被替换为:#include <iostream>#include <iomanip>using namespace std;2 在 C+,我们仍然可以使用 C 运行库中的p

28、rintf 和 scanf 或者 C 的其它 I/O 函数。与 C 程序使用这些函数一样,需要在包含 stdio.h。3 在 Java,输入输出操作也是通过包装了输入输出功能的 I/O 流类对象完成的。但 Java 的I/O 流类在结构、功能和调用上与 C+ 的 I/O流类有着不少差别,这些差别会在第八章中做适当的。2.3.3 灵活的局部变量说明局部变量f() int i;cin >> i; int j = 25;出现在程序的。例如:cout << i << , << j;甚至可以在某些语句表中,例如:for(int i = 0; i <

29、5; i+)一般认为,在大函数(代码长)中,在最靠近使用变 量的位置说明变量较为方便合理;而在小函数(代码 短)中,把局部变量集中在函数开始说明较好。2.3.4 结构、在 C+ 中,用和枚举名可直接作为类型名struct 定义的结构名,union 定义的联合名和 enum 定义的枚举名都是类型名。例如:enum bool FALSE, TRUE; struct stringchar* str; int length;bool done; string str;/ 定义枚举类型 bool/ 定义结构类型 string/ 定义 bool 类型变量 done/ 定义 string 类型变量 str如

30、果上述自定义类型只使用一次,则定义自定义类型时可以没有类型名。例如:enum FALSE, TRUE done; structchar* str; int length; str;/ 定义枚举类型变量 done/ 定义结构类型变量 str例2-21 使用无名编写显示计算机某些系统参数。2.3.5 const 修饰符const 可以修饰任何类型变量,指针变量。变量一旦被 const 修饰说明,该变量便成为一个,这与使用预编译命令 #define 定义的结果相同。在修饰指针变量时,const 的位置不同,含义和结果均不同:1 指向的指针:指向数据的指针变量,如:const char* name =

31、 "Chen"“Chen” 的地址,该地址中即 name 指向字符串的字符串是一个不name3 = a;改变的。例如,语句:是的,但 name 是可改变的,例如,语句:name = "Zhang"是合法的。2 常指针:指向数据变量的char* const name = "Chen"指针,例如:即放置字符串的地址是,不改变,例如:name = "Zhang"是的。而字符串的以改变,例如:name3 = a;是合法的。3 指向的常指针:指向数据的指针,例如:const char* const name = "

32、Chen"即放置字符串的地址和字符串本身均为,不改变,例如:name3 = a;name = "Zhang"都是的。4 使用 const 修饰符的几点说明: 如果用 const 定义整型,可省略类型说明。一旦定义,程序的任何地方都不更改,缺省值为零。 const 是一个修饰符,用 const 定义的拥有类型说明,因此具有良好的编译时检测性。 const 消除了 #define 的某些不安全性。例2-11 描述了使用 #define 宏定义出现的不安全。分析:为什么执行结果不是预想的那样:T2 is 0 而是 T2 is 2 呢?这是因为使用 #define 定义的

33、在预编译中是进行宏替换,因此 T2 在语句: cout << "T2 is " << T2 << endl;中被替换为:cout << "T2 is " << a + a a + a << endl;如果样的错误。用 const 取代 #define,将引起这例2-12 使用 const 替换 #define。 函数的参数也可以用 const 说明,使得实参在函数执行过程中不被修改。大多数 C+ 编译器能对具有 const 参数的函数进行优化。 ANSI 制定的 C 标准(简称 AN

34、SI C 标准)也采用了 const 但与 C+ 中的 const 略有差别。 const 修饰符也可以与用户自定义类型一起使用,自定义类型(常对象)。 const 还可以将类的成员函数见第三章的有关内容。为只读函数,祥 Java 的 final 相当于 C+ 的 const。2.3.6 函数原型由于 C 和 C+ 的编译器都不具备“向前看”的能力,因此在函数被调用之前应进行或定义。在 C 程序中函数的并不是强制的,编译不严格。例如,用于两个整数值大小的函数 max 就可以如下多种方式:int max(int x, int y); int max(int, int);max(int, int)

35、;在 C+,函数原型是必须的,的语法必须遵循如下规则:返回值类型名函数名 (参数表);但如果被调用函数的定义出现在该函数的调用语句之前,则不必再单独给出该函数的原型定义的首部就起到了函数原型的使用函数原型的几点说明:,因为函数作用。 函数原型的参数表中可以不包含形参名,但必须指定每个形参的类型,例如:int max(int, int);虽然这样的原型是合法的,但加上参数名的原型 将更加清楚,使得程序的可读性好。 函数的说明部分(函数首部)与原型的形式基本相同,但函数说明部分中的参数必须给出形结尾的分号“;”。参名,且不 函数的参数必须放在函数名后的括号内,不可将参数说明放在函数说明部分与函数体

36、之间。 主函数 main 不必进行原型说明。 函数原型或首部中无函数类型(C+默认该函数的类型为 int。main), 如果函数确实无返回值,则必须在函数原型或首部中该函数的类型为 void。 如果函数原型中无参数,C+ 默认该函数的参数为空(void)。 在一个程序文件的 #include<> 语句所的头文件中包含的是该程序文件的代码在进行编译时所需要调用的函数的原型说明。因此,可以将程 序中自定义函数的原型说明集中在相应的头文件 中,并且在需要调用这些自定义函数的程序文件中增加 #include 语句,用于相应的自定义函数头文件。 Java 不要求(函数)调用之前进行。2.3.

37、7 内置(联)函数中增加前缀 “inline”,此函数就被在函数为内置函数。C+ 编译器会将所有对内置函数的调用替换为该函数的编译代码,而不是对该函数编译代码的调用。其作用是能减少调用开销,加快执行速度,但可能会增加内存开销。例2-13 给出了一个简单的内置函数使用内置函数的几点说明: 内置函数在调用之前必须进行完整的定义,否则编译器将不知道用什麽代码来置换调用表。因此,一般情况下应该将内置函数的完整定义放置在头文件(.h 或 .hpp)中或放置在源文件(.cpp)中所有对该函数调用之前的位置。 C+ 中的内置函数与 C 中带参数的宏定义具有相同的作用和相似的机理,但消除了宏定义的不安全因素。

38、例2-14 描述了使用 #define 产生的不安全问题。分析:程序运行的前三个结果与预期的相符,但第四个结果却不是希望的 1+2 double is 6。产生这样的结果的仍然是宏定义代码在预编译过程中被直接替换所致。因此,第二条输出语句:cout << "1+2 doubled is " << doub(1 + 2) << endl;被替换为:cout << "1+2 doubled is " << 1 + 2 * 2 << endl;使用内置函数取代宏定义,就可以避免上述错误。例

39、2-15 描述了用内置函数替代 #define 的结果。 使用内置函数的原则是兼顾时空:当函数代码短,提高执行速度是主要,并且内存和磁盘资源充足时,可使用内置函数。若函数代码长,并且调用频繁,则不要将函数定义为内置函数,否则程 序会变得很长。 有些 C+ 版本,例如 Visual C+ 会根据情况,自动决定是否接受内置函数的申请。拒绝内置函数申请的判别标准在不同的 C+ 编译环境中是不同的,例如,在 Visual C+ 中,如果申请内置的函数代码超过八行(含八行),就会被拒绝。递归函 数和有循环结构的函数也会被拒绝内置。2.3.8 函数重载(Overload)使用 C 语言编程时,如果要编写施

40、加于不同类型数据的操作函数时,必须使用不同的函数名。例如:int max1(int a, int, b, int c);double max2(double a, double b, double c); long max3(long a, long b, long c);在 C+ 中,两个或两个以上的函数,只要它们的参数类型和参数个数不同,就可以采用相同的函数名,这些具有相同名称的函数称为重载函数。例如:int max(int a, int, b, int c);double max(double a, double b, double c); long max(long a, long b

41、, long c);载函数的两点说明: 重载函数不同版本的依据是参数的类型和个数必须有所不同。如果同名函数的参数类型和个数相同,而函数类型不同,将会引起编译时的二义性错误。例如:int mul(int x, int y); double mul(int x, int y); 函数的重载机制用于同类功能的不同操作定义,运算符(函数)重载是最典型的应用。应避免因函数的随意重载引起功能调用的。调用重载函数的匹配过程是按如下步骤完成的: 从重载函数集合中找出准确匹配(形参类型、个数、顺序与实参完全一致)。如果准确匹配且唯一,则匹配。 如果准确匹配失败,则进行参数类型的合法转换。如果转换匹配且唯一,则匹

42、配。,或虽然 如果准确匹配和转换匹配均不不唯一,则匹配失败。但与 C+ 一样,Java 也支持函数重载机制。二者的差别在于 Java 对转换匹配的限制要大大严格于 C+,一些 C+的重载函数匹配在 Java 中是不的。例2-17对算术平方函数进行重载定义,使之能适应三种数据类型值计算平方的需要。例2-18使用函数重载机制定义从能从三种不同数据类型的数组中检索最大值函数和检索最小值函数。例2-19定义具有不同的参数个数的重载函数。2.3.9 带有缺省参数的函数如果函数的某些参数在大多数调用时总是传递相同的实参值,则 C+在函数原型或无原型的函数首部中为这些参数指定缺省(实参)值,例如:int s

43、pecial(int x = 5, float y = 5.3);具有缺省参数值的函数被调用时,如果没有为具有缺 省值的形参传递实参值,则缺省值就被使用;否则调 用者传递的实参值替代缺省值。例2-16 定义带有缺省参数的销售税计算函数,并在主分两种情况调用该函数。使用缺省参数的几点说明: 在函数原型或函数首部中,所有有缺省值形参都必须出现在无缺省值形参的右边。例如:int fun(int i, int j = 5, int k);int fun(int i, int k, int j = 5);/ 错误/ 正确 在具有缺省参数的函数被调用时,若某个缺省值被使用,则其后的实参值皆必须采用缺省值。

44、 例如,对函数 int special(int x = 5, float y = 5.3) 的调用:special(,21.5);/ 是错误的 定义带有缺省参数的重载函数时,应避免调用时的二义性错误。例如,如果对于重载函数 max:int max(int a, int b, int c = 100); int max(int a, int d);进行如下调用:max(5, 23);编译系统就会因为无法判别调用哪一个 max 版本,而显示二义性出错信息。2.3.10 名字空间和作用域运算符所谓名字空间就是一个可以由编程者命名的标识符的作用域。在一个给定的名字空间中可以和定义一些成员(变量、函数、

45、类等)标识符,使得在逻辑上、结构上相关的成员处于同一作用域,而将不相关 的成员分隔在不同的作用域中。在一个名字空间中封 装成员代码的基本语法是:namespace ModuleName 其中,namespace 是定义名字空间的关键字,紧随其后的是编程者为名字空间名,例如, ModuleName,而花括弧 和 表示该名字空间管辖的作用域。例如:namespace Module1void foo() cout << “Module foo() invoked” << endl; int bar(int x) return x;typedef string* T;表示函数

46、foo 和 bar,以及类型 T 均属于名字空间Module1 所管辖。为了在名字空间的外部必须使用名字空间限定表Module1:foo();名字空间的内部成员,。例如:其中“:”是作用域运算符,该运算符是一个双目运算符,其语法和语义如下:名字空间名:标识符 该表表示要的是名字空间名所指定的作用域中的标识符所指示的函数、变量等 。 表的左操作数为空,即 : 标识符,表示全局标识符所指示的函数、变量等 。 表的右操作数不为空,即,名字空间名:是错误的。使用名字空间限定表可以使在同一程序作用域范围内处于不同名字空间的相同标识符所指示的函数、变量变得轻而易举。不难看出,名字空间和作用域运算符为函数、

47、变量等名和提供了极大的方便。如果在程序的一段代码作用域范围内属于同一名字空间中的成员,又想避免使用名字空间限定表所引起的麻烦,则可使用 using 指令,例如:int main()using namespace Module1; foo();注意,只有当名字空间所管辖成员的标识符和全局定义的标识符不的情况下,才可以通过指令 using 使用名字空间中的所有成员,否则将可能出现二义性错误。例如:void foo() cout << “Global-level foo() invoked” << endl; void main() using namespace Modul

48、e1;foo();/ 产生二义性错误使用作用域运算符就可以解决这一。例如:void foo() cout << “Global-level foo() invoked” << endl; void main() void foo() cout << “Local-level foo() invokedn”;Module1:foo();:foo(); foo();/Module 封装的 foo()全局的 foo()局部的 foo()使用 using 不仅可以作为指令导致一个名字空间中所有成员在当前作用域中可见,还可以间中的一个特定成员名字。例如:using M

49、odule1:foo;名字空一个名字空间中引入其他名字空间或其他名字空间的某些成员,使后者成为前者的成员。例如:namespace Module1 class X ; namesapce Module2void foo() cout << “foo of Module2 invoked” << endl; void bar() cout << “bar of Module2 invoked” << endl;namespace Module3using namespace Module1; typedef X Y;using Module2:fo

50、o; class Z ;void main()Module3:X x; Module3:Y y; Module3:foo();Module3:bar();/ 错误,Module3 中不bar名字空间嵌套,并为已经定义的名字空间定义一个别名。例如,名字空间 N1 的定义如下:#include <string> namespace N1 typedef int Type; namespace N2 typedef int* Type; namespace N3 typedef string Type; namespace N4 typedef string* Type;void mai

51、n() using namespace N1; Type x = 10;cout << x << endl;N1:N2:Type p = &x; cout << *p << endl;N1:N2:N3:Type str(“hello”);cout << str << endl ;/ Type 是 int/ 10/ Type 是 int*/ 10/ Type 是 string/ “hello”N1:N2:N3:N4:Type q = &str; / Type 是 string*cout << *q

52、 << endl ;/ 输出 “hello”namespace N_FOUR = N1:N2:N3:N4;/ 定义名字空间别名N_FOUR:Type ptr = &str;cout << *ptr << endl;/ 输出 “hello”名字空间的使用,使得程序的模块化得以方便、安全的实现,否则将会遇到很多。例如:如果在一个/ one.hchar func(char);包含如下两个头文件:class String . ;/ somelib.hclass String . ;这是不的,因为两个头文件中都定义了自定义类 String,标识符是相互需要使用

53、多个不同的库( 常可能发生的。的。但是在实际系统中)时,上述情况是非如何解决这种呢?使用名字空间将不同的库隔离开,是解决这类/ one.h namespace one 的好。例如:char func(char);class String . ;/ somelib.h namespace Somelib class String . ;由于两个同名的类 String 分别属于两个不同的名字空间,所以它们时产生。在 Java 中程序的模块化是通过构造程序包 package实现的。例如将一个类 TestOne 定义在一个程序包packageX 中: packege packageX; public

54、class TestOne public void print() System.out.println(“print of packageX.TestOne invoked”);public static void main(String args) TestOne testone = new TestOne(); testone.print();如果要在一个执行类 TestOne,则需要通过import 导入包含类 TestOne 的程序包 packageX。import packageX.*; public class TestTwo TestOne testone = new TsetOne();public void print() System.out.println(“print of TestTwo invoked”);public static void main(String args) TestTwo testtwo = new TestTwo(); testtwo.pri

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论