面向对象程序设计之多态性与虚函数

上传人:新** 文档编号:568831776 上传时间:2024-07-27 格式:PPT 页数:66 大小:875.50KB
返回 下载 相关 举报
面向对象程序设计之多态性与虚函数_第1页
第1页 / 共66页
面向对象程序设计之多态性与虚函数_第2页
第2页 / 共66页
面向对象程序设计之多态性与虚函数_第3页
第3页 / 共66页
面向对象程序设计之多态性与虚函数_第4页
第4页 / 共66页
面向对象程序设计之多态性与虚函数_第5页
第5页 / 共66页
点击查看更多>>
资源描述

《面向对象程序设计之多态性与虚函数》由会员分享,可在线阅读,更多相关《面向对象程序设计之多态性与虚函数(66页珍藏版)》请在金锄头文库上搜索。

1、Object-OrientedProgramminginC+第六章多态性与虚函数C+ 6- 1 6.1 多态性的概念多态性的概念多态性多态性( polymorphism ) 是面向对象程序设计的重要是面向对象程序设计的重要特征。一个算法语言如果只支持类,而不支持多态,只能说特征。一个算法语言如果只支持类,而不支持多态,只能说是基于对象的语言,如是基于对象的语言,如Ada, VB。C+支持多态性,在支持多态性,在C+程序设计中能够实现多态性。利用多态性,可以设计和扩展程序设计中能够实现多态性。利用多态性,可以设计和扩展一个易于扩展的系统。一个易于扩展的系统。l什么叫多态?什么叫多态?u多态的意思

2、是一种事物的多种形态。多态的意思是一种事物的多种形态。u在在C+中,中,是指具有不同功能的函数可以用同一个函数名是指具有不同功能的函数可以用同一个函数名。u面向对象方法中一般是这样描述多态性的:向不同的对象面向对象方法中一般是这样描述多态性的:向不同的对象发送同一个消息,不同的对象在接收时会产生不同的行为发送同一个消息,不同的对象在接收时会产生不同的行为(即方法)。(即方法)。C+ 6- 2 写出程序运行结果写出程序运行结果#include #include Using namespace std;class studentpublic: student (int n,string nam,

3、float s) num= n; name= nam; score= s; void display( ) cout“num:”num “name:”name “score:”scoreendl; protected: int num; string name; float score;class graduate : public studentpublic: graduate (int n, string nam, float s, float p): student (n,nam,s), pay(p) void display( ) cout“num:”num “name:”name “

4、score:”score “pay:”paydisplay( ); pt = &g1; pt-display( ); C+ 6- 3 6.1 多态性的概念多态性的概念我们其实已经接触过多态性的现象。如函数的重载我们其实已经接触过多态性的现象。如函数的重载多态性分类多态性分类:从系统实现的角度看,多态性分为以下两类:从系统实现的角度看,多态性分为以下两类:u静态多态性:又称编译时的多态性。如函数重载属于静态静态多态性:又称编译时的多态性。如函数重载属于静态多态性。多态性。u动态多态性:有称为运行时的多态性。它主要表现为虚函动态多态性:有称为运行时的多态性。它主要表现为虚函数数( virtual

5、function )。C+ 6- 4 6.3 虚函数虚函数能否用一个调用形式,既能调用派生类的函数,又能调能否用一个调用形式,既能调用派生类的函数,又能调用基类同名函数?用基类同名函数?C+中的虚函数就是用来解决这一问题。中的虚函数就是用来解决这一问题。l虚函数的作用虚函数的作用:虚函数的作用是允许在派生类中重新定义与:虚函数的作用是允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数。和派生类中的同名函数。C+ 6- 5 6.3 虚函数虚函数#include #include class stud

6、entpublic: student (int n,string nam, float s) num= n; name= nam; score= s; void display( ) cout“num:”num “name:”name “score:”scoreendl; protected: int num; string name; float score;class graduate : public studentpublic: graduate (int n, string nam, float s, float p): student (n,nam,s), pay(p) void

7、display( ) cout“num:”num “name:”name “score:”score “pay:”paydisplay( ); / 指向基类对象指向基类对象s1 pt = &g1; pt-display( ); / 指向派生类对象指向派生类对象g1,仅仅输出了派生类的基类数据成员,因为它输出了派生类的基类数据成员,因为它调用的是基类成员函数调用的是基类成员函数display! 假如想输出派生类的全部数据,当然可以采用下面两种方法之一:假如想输出派生类的全部数据,当然可以采用下面两种方法之一:n通过派生类对象名通过派生类对象名g1,调用派生类对象的成员函数:,调用派生类对象的成员

8、函数:g1.display( );n定义一个指向派生类的指针定义一个指向派生类的指针ptr,并指向,并指向g1,然后用,然后用ptr-display( )。C+ 6- 6 6.3 虚函数虚函数 我们可以用虚函数可以顺利解决这一问题。方法是:我们可以用虚函数可以顺利解决这一问题。方法是:u在基类在基类student 中声明中声明 display函数时,在最左边加上一个关键字函数时,在最左边加上一个关键字virtual :virtual void display( ); 就可以就可以student类的类的display函数声明为虚函数,程序其它部分不变编函数声明为虚函数,程序其它部分不变编译运行后

9、,可见,使用译运行后,可见,使用pt-display( ),的确将,的确将graduate类对象类对象 g1 的全部的全部数据显示了出来,说明它调用的是数据显示了出来,说明它调用的是g1 的成员函数的成员函数 display。u在派生类中重新定义该函数,要求函数名、函数类型、参数表完全相同。在派生类中重新定义该函数,要求函数名、函数类型、参数表完全相同。但不加但不加virtual关键字。关键字。u只在类里的成员函数声明时,加上关键字只在类里的成员函数声明时,加上关键字virtual,在类外定义定义虚函数,在类外定义定义虚函数时,不加时,不加virtual关键字。关键字。u定义一个指向定义一个指

10、向基类对象基类对象的指针,并使她指向同一类中的某一对象;的指针,并使她指向同一类中的某一对象;u通过该指针标量调用此虚函数,此时调用的就是指针变量指向的对象的同通过该指针标量调用此虚函数,此时调用的就是指针变量指向的对象的同名函数,而不是基类的同名函数!名函数,而不是基类的同名函数!C+ 6- 7 6.3 虚函数虚函数通过使用虚函数和指针,就能方便地调用同一类族中不同通过使用虚函数和指针,就能方便地调用同一类族中不同类对象的同名函数,只要先用基类指针指向该对象即可。类对象的同名函数,只要先用基类指针指向该对象即可。#include #include class studentpublic: s

11、tudent (int n,string nam, float s) num= n; name= nam; score= s; virtual void display( ) cout“num:”num “name:”name “score:”scoreendl; protected: int num; string name; float score;class graduate : public studentpublic: graduate (int n, string nam, float s, float p): student (n,nam,s), pay(p) void disp

12、lay( ) cout“num:”num “name:”name “score:”score “pay:”paydisplay( ); / 指向基类对象指向基类对象s1 pt = &g1; pt-display( ); / 指向派生类对象指向派生类对象g1,调调用用g1的显示函数的显示函数display,打印出,打印出g1全全部数据成员部数据成员C+ 6- 8 6.3 虚函数虚函数将函数重载与虚函数比较,可见:将函数重载与虚函数比较,可见:u函数重载是解决的是同一层次上的同名函数的问题。是横函数重载是解决的是同一层次上的同名函数的问题。是横向重载。向重载。u虚函数解决的是不同派生层次上的同名函

13、数的问题。相当虚函数解决的是不同派生层次上的同名函数的问题。相当于纵向重载。于纵向重载。u同一类族的虚函数的首部是相同的;而重载函数的首部不同一类族的虚函数的首部是相同的;而重载函数的首部不相同(参数表不能相同)。相同(参数表不能相同)。C+ 6- 9 6.3 虚函数虚函数l静态关联与动态关联静态关联与动态关联C+在编译或运行时,对多个同名函数究竟调用哪一个在编译或运行时,对多个同名函数究竟调用哪一个函数,需要一定的机制来确定。这种确定调用的具体对象的函数,需要一定的机制来确定。这种确定调用的具体对象的过程称为过程称为“关联关联( binding )”,即把函数名与某一个类对象捆,即把函数名与

14、某一个类对象捆绑在一起。绑在一起。函数重载,在编译时就可确定其调用的函数是哪一个;函数重载,在编译时就可确定其调用的函数是哪一个;通过对象名调用虚函数,在编译时也可确定其调用的虚函数通过对象名调用虚函数,在编译时也可确定其调用的虚函数属于哪一个类。其过程称为属于哪一个类。其过程称为“静态关联静态关联( static binding ),因为是在运行前进行关联的,又成为早期关联因为是在运行前进行关联的,又成为早期关联( early binding )。C+ 6- 10 6.3 虚函数虚函数通过指针和虚函数的结合,在编译阶段是没法进行关联的,通过指针和虚函数的结合,在编译阶段是没法进行关联的,因为

15、编译只作静态的语法检查,光从语句形式因为编译只作静态的语法检查,光从语句形式pt-display( )无无法确定调用的对象,也就没法关联。法确定调用的对象,也就没法关联。出现这种情况,我们可以在运行阶段来处理关联。在运行出现这种情况,我们可以在运行阶段来处理关联。在运行阶段,基类指针先指向某一个对象,然后通过指针调用该对象的阶段,基类指针先指向某一个对象,然后通过指针调用该对象的成员函数。此时调用哪个函数是确定的,没有不确定因素。例如成员函数。此时调用哪个函数是确定的,没有不确定因素。例如语句语句 pt = &g1; pt-display( ); 非常确定的是调用非常确定的是调用g1对象的成员

16、对象的成员函数函数display。这种情况由于是在运行阶段将虚函数与某一类对象这种情况由于是在运行阶段将虚函数与某一类对象“绑定绑定”在一起的,因此称为在一起的,因此称为“动态关联动态关联( dynamic binding ),或,或“滞后关联滞后关联( late binding )”。C+ 6- 11 6.3 虚函数虚函数l使用虚函数,要注意使用虚函数,要注意u只能用只能用virtual 声明类的成员函数,类外的普通函数不能声明类的成员函数,类外的普通函数不能声明成虚函数,因为它没有继承的操作。声明成虚函数,因为它没有继承的操作。u一个成员函数被声明成虚函数后,在同一类族中的类就不一个成员函

17、数被声明成虚函数后,在同一类族中的类就不能再定义一个非能再定义一个非virtual的、但与该函数具有相同参数表和的、但与该函数具有相同参数表和返回类型的同名函数。返回类型的同名函数。u使用虚函数,系统要有一定的空间开销。当一个类带有虚使用虚函数,系统要有一定的空间开销。当一个类带有虚函数时,编译系统会为该类构造一个虚函数表函数时,编译系统会为该类构造一个虚函数表( virtual function table, vtable ),它是一个指针数组,存放每个,它是一个指针数组,存放每个虚函数的入口地址。虚函数的入口地址。系统在进行动态关联时的时间开销是很少的,所以多态系统在进行动态关联时的时间开

18、销是很少的,所以多态性运行效率非常高。性运行效率非常高。C+ 6- 12 6.3 虚函数虚函数l什么情况下使用虚函数?什么情况下使用虚函数?u成员函数所在的类是否会作为基类?成员函数被继承后有成员函数所在的类是否会作为基类?成员函数被继承后有没有可能发生功能变化,如果两个因素都具备,就应该将没有可能发生功能变化,如果两个因素都具备,就应该将它声明成虚函数。它声明成虚函数。u如果成员函数被继承后功能不变,或派生类用不到该函数,如果成员函数被继承后功能不变,或派生类用不到该函数,就不要声明成虚函数。就不要声明成虚函数。u应考虑对成员函数的访问是通过对象名还是基类指针,如应考虑对成员函数的访问是通过

19、对象名还是基类指针,如果是通过基类指针或引用访问,则应当声明为虚函数。果是通过基类指针或引用访问,则应当声明为虚函数。u有时基类中定义虚函数时并不定义它的函数体,即函数体有时基类中定义虚函数时并不定义它的函数体,即函数体为空。其作用只是定义了一个虚函数名,具体功能留给派为空。其作用只是定义了一个虚函数名,具体功能留给派生类添加(生类添加(6.4 节会讨论这种情况)。节会讨论这种情况)。C+ 6- 13 6.3 虚函数虚函数l虚析构函数虚析构函数u问题的引出:我们知道,当派生类对象撤消时,系统先调用派生类析问题的引出:我们知道,当派生类对象撤消时,系统先调用派生类析构函数,再调用基类析构函数。但

20、是,如果用构函数,再调用基类析构函数。但是,如果用new 运算符建立了一个运算符建立了一个派生类临时对象,但用一个基类指针指向它,当程序用带指针参数的派生类临时对象,但用一个基类指针指向它,当程序用带指针参数的delete 撤消对象时,会发生让人不能接受的情况:系统只析构基类对撤消对象时,会发生让人不能接受的情况:系统只析构基类对象,而不析构派生类对象:象,而不析构派生类对象:class pointpublic: point( ) point( ) cout“析构基类对象析构基类对象”endl; ;class circle : public pointpublic: circle( ) cir

21、cle ( ) cout“析构派生类对象析构派生类对象”endl; private: int radius;int main( ) point *p = new circle; / 指针为指向基类对象指针,指针为指向基类对象指针, / 但实际指向临时派生类对象但实际指向临时派生类对象 delete p; return 0;C+ 6- 14 6.3 虚函数虚函数实际上,程序只析构了基类对象,而没有析构派生类对实际上,程序只析构了基类对象,而没有析构派生类对象,为什么呢?因为指针象,为什么呢?因为指针p 为基类指针,系统认为它只有基为基类指针,系统认为它只有基类对象,而与派生类对象无关。实际上,由

22、于该指针被指向类对象,而与派生类对象无关。实际上,由于该指针被指向了一个临时派生类对象,所以还应该这个临时的析构派生类了一个临时派生类对象,所以还应该这个临时的析构派生类对象。对象。u解决的办法:解决的办法:可以将基类的析构函数声明为虚析构函数。可以将基类的析构函数声明为虚析构函数。如:如: virtual point( ) cout“析构基类对象析构基类对象”endl; 程序其它部分不动,就行了。程序其它部分不动,就行了。当基类的析构函数被定义成当基类的析构函数被定义成virtual,无论指针指向同一,无论指针指向同一类族中的哪一个对象,当撤消对象时,系统会采用动态关联,类族中的哪一个对象,

23、当撤消对象时,系统会采用动态关联,调用相应的析构函数,清理该对象,然后再析构基类对象。调用相应的析构函数,清理该对象,然后再析构基类对象。C+ 6- 15 6.4 纯虚函数与抽象类纯虚函数与抽象类前面已经提到,有时在基类中将某一成员函数定为虚函前面已经提到,有时在基类中将某一成员函数定为虚函数并不是基类本身的需要,而是派生类的需要。在基类中预数并不是基类本身的需要,而是派生类的需要。在基类中预留一个函数名,具体功能留给派生类根据需要去定义。留一个函数名,具体功能留给派生类根据需要去定义。在上一节中基类在上一节中基类point 中有定义面积中有定义面积area函数,是因为函数,是因为“点点”没有

24、面积的概念。但是,其直接派生类没有面积的概念。但是,其直接派生类circle和间接和间接派生类派生类cylinder却都需要却都需要area 函数,而且这两个函数,而且这两个area 函数的函数的功能还不相同,一个是求圆面积,一个是求圆柱体表面积。功能还不相同,一个是求圆面积,一个是求圆柱体表面积。也许会想到,在基类也许会想到,在基类point 中加一个中加一个area 函数,并声明函数,并声明为虚函数:为虚函数:virtual float area ( ) const return 0; 其返回其返回0表示表示“点点”没有面积。其实,在基类中并不使没有面积。其实,在基类中并不使用这个函数,其

25、返回值也没有意义。用这个函数,其返回值也没有意义。C+ 6- 16 6.4 纯虚函数与抽象类纯虚函数与抽象类为简化起见,可以不写出这种无意义的函数体,只给出为简化起见,可以不写出这种无意义的函数体,只给出函数的原型,并在后面加上函数的原型,并在后面加上“=0”,如:,如:virtual float area( ) const =0 ; / 纯虚函数纯虚函数这就将这就将area声明为一个纯虚函数声明为一个纯虚函数(pure virtual function)l纯虚函数的声明形式纯虚函数的声明形式virtual 函数类型函数类型 函数名函数名( 参数表参数表 ) =0;说明说明u纯虚函数没有函数体

26、;纯虚函数没有函数体;u最后的最后的“=0”不表示函数值返回不表示函数值返回0,它只是形式上的作用,它只是形式上的作用,告诉编译系统:这是纯虚函数,告诉编译系统:这是纯虚函数,u这是一个声明语句,以分号结尾。这是一个声明语句,以分号结尾。u如果基类中声明了纯虚函数,但派生类中定义该函数,则该如果基类中声明了纯虚函数,但派生类中定义该函数,则该虚函数在派生类中仍为纯虚函数。虚函数在派生类中仍为纯虚函数。C+ 6- 17 6.4 纯虚函数与抽象类纯虚函数与抽象类l纯虚函数的作用纯虚函数的作用是在基类中为其派生类保留一个函数的名字,以便派生是在基类中为其派生类保留一个函数的名字,以便派生类根据需要对

27、它进行定义。如果基类中没有保留函数名,则类根据需要对它进行定义。如果基类中没有保留函数名,则无法实现多态性。无法实现多态性。C+ 6- 18 6.4 纯虚函数与抽象类纯虚函数与抽象类l抽象类抽象类u什么叫抽象类?什么叫抽象类?一般声明了一个类,用来定义若干对象。一般声明了一个类,用来定义若干对象。但有些类并不是用来生成对象,而是作为基类去建立派生但有些类并不是用来生成对象,而是作为基类去建立派生类。类。这种不用来定义对象,而只作为一种基本类型用做继这种不用来定义对象,而只作为一种基本类型用做继承的类,就叫抽象类承的类,就叫抽象类( abstract class )。由于抽象类常作。由于抽象类常

28、作为基类,我们也称为抽象基类为基类,我们也称为抽象基类( abstract base class )。比如,凡是包含纯虚函数的类都叫抽象类。因为纯虚函比如,凡是包含纯虚函数的类都叫抽象类。因为纯虚函数不能被调用,包含纯虚函数的类无法建立对象。数不能被调用,包含纯虚函数的类无法建立对象。u抽象类的作用抽象类的作用:是作为一个类族的共同基类。即,为一个:是作为一个类族的共同基类。即,为一个类族提供一个公共接口。类族提供一个公共接口。一个类层次结构中可以不包含任何抽象类,每一层次的一个类层次结构中可以不包含任何抽象类,每一层次的类都可以建立对象。但是,许多系统的顶层是一个抽象类,类都可以建立对象。但

29、是,许多系统的顶层是一个抽象类,甚至顶部有好几层都是抽象类。甚至顶部有好几层都是抽象类。C+ 6- 19 6.4 纯虚函数与抽象类纯虚函数与抽象类如果由抽象类所派生出的新类中对基类的所有纯虚函数如果由抽象类所派生出的新类中对基类的所有纯虚函数都进行了定义,这个派生类就不是抽象类,可以被调用,成都进行了定义,这个派生类就不是抽象类,可以被调用,成为可以用来定义对象的具体类为可以用来定义对象的具体类( concrete class )。如果由抽象类所派生出的新类中对基类的所有纯虚函数如果由抽象类所派生出的新类中对基类的所有纯虚函数都没有进行定义,这个派生类就仍然是抽象类。都没有进行定义,这个派生类

30、就仍然是抽象类。虽然抽象类不能定义对象,但可以定义指向抽象类的数虽然抽象类不能定义对象,但可以定义指向抽象类的数据的指针。当派生类成为具体类之后,就可以用这种指针向据的指针。当派生类成为具体类之后,就可以用这种指针向派生类对象,然后通过该指针调用虚函数,实现多态性操作。派生类对象,然后通过该指针调用虚函数,实现多态性操作。C+ 6- 20 编程练习:编程练习:定义虚函数,基类为定义虚函数,基类为SHAPE,派生出圆形、矩派生出圆形、矩形、三角形类。形、三角形类。C+ 6- 21 l#include lusing namespace std;l/定义抽象基类定义抽象基类Shapelclass S

31、hapelpublic:l/定义纯虚函数定义纯虚函数l;l/定义定义Circle类类lclass Circle:public Shapelpublic:lCircle(double r):radius(r) l/定义虚函数定义虚函数l protected:l double radius; /半径半径l;l/定义定义Rectangle类类lclass Rectangle:public Shapelpublic:l Rectangle(double w,double h):width(w),height(h)l/定义虚函数定义虚函数l protected:l double width,height

32、; l;lclass Triangle:public Shapelpublic:l Triangle(double w,double h):width(w),height(h)l/定义虚函数定义虚函数l protected:l double width,height; l;C+ 6- 22 l#include lusing namespace std;l/定义抽象基类定义抽象基类Shapelclass Shapelpublic:l virtual double area() const =0; /纯虚函数纯虚函数l;l/定义定义Circle类类lclass Circle:public Shap

33、elpublic:lCircle(double r):radius(r) l virtual double area() const return 3.14159*radius*radius; /定义虚函定义虚函数数l protected:l double radius; /半径半径l;l/定义定义Rectangle类类lclass Rectangle:public Shapelpublic:l Rectangle(double w,double h):width(w),height(h)l virtual double area() const return width*height; /定

34、义虚函数定义虚函数l protected:l double width,height; l;lclass Triangle:public Shapelpublic:l Triangle(double w,double h):width(w),height(h)l virtual double area() const return 0.5*width*height; /定义虚函数定义虚函数l protected:l double width,height; l;C+ 6- 23 续:定义一个函数续:定义一个函数printArea,以对象为形参,以对象为形参,输出三种形状的面积输出三种形状的面积

35、lint main()ll Circle circle(12.6); /建立建立Circle类对象类对象circlel coutarea of circle =; l printArea(circle); /输出输出circle的面积的面积l Rectangle rectangle(4.5,8.4); /建立建立Rectangle类对象类对象rectanglel coutarea of rectangle =; l printArea(rectangle); /输出输出rectangle的面的面积积l Triangle triangle(4.5,8.4); /建立建立Triangle类对象类对

36、象 l coutarea of triangle =;l printArea(triangle); /输出输出triangle的面积的面积l return 0;lC+ 6- 24 l/输出面积的函数输出面积的函数lvoid printArea(const Shape &s)lcouts.area()endl; C+ 6- 25 6.4 纯虚函数与抽象类纯虚函数与抽象类多态性把操作细节留给类的设计者(专业人员)去完成,多态性把操作细节留给类的设计者(专业人员)去完成,而让编程人员(类的使用者)只需做一些宏观性的工作,告而让编程人员(类的使用者)只需做一些宏观性的工作,告诉系统做什么,不必考虑怎么

37、做,简化了应用程序的编码工诉系统做什么,不必考虑怎么做,简化了应用程序的编码工作。作。因此有人说,多态性是开启继承功能的钥匙。因此有人说,多态性是开启继承功能的钥匙。Object-OrientedProgramminginC+第七章输入输出流C+ 6- 27 第一章第一章 C+的初步知识的初步知识第二章第二章 类和对象类和对象第三章第三章 再论类和对象再论类和对象第四章第四章 运算符重载运算符重载第五章第五章 继承与派生继承与派生第六章第六章 多态性与虚函数多态性与虚函数第七章第七章 输入输出流输入输出流第八章第八章 C+工具工具C+ 6- 28 7.1 C+的输入与输出的输入与输出7.2 标

38、准输出流标准输出流7.3 标准出入流标准出入流7.4 文件操作与文件流文件操作与文件流7.5 字符串流字符串流C+ 6- 29 7.1 C+的输入和输出的输入和输出l输入输出的含义输入输出的含义:从操作系统角度看,每一个与主机相连的输入输:从操作系统角度看,每一个与主机相连的输入输出设备都被看做一个文件。终端键盘是输入文件,终端显示器是输出设备都被看做一个文件。终端键盘是输入文件,终端显示器是输出文件。磁盘或光盘也可以被看作是输入输出文件。出文件。磁盘或光盘也可以被看作是输入输出文件。u程序的输入:指的是从输入文件将数据传送给程序;程序的输入:指的是从输入文件将数据传送给程序;u程序的输出:指

39、的是从程序将数据输出给输出文件。程序的输出:指的是从程序将数据输出给输出文件。lC+的输入输出包括以下三个方面的内容的输入输出包括以下三个方面的内容:u标准设备输入输出,从键盘输入。输出到显示器。简称标准标准设备输入输出,从键盘输入。输出到显示器。简称标准I/O。u以外存储器文件为对象的输入输出。指从磁盘文件中输入数据,以外存储器文件为对象的输入输出。指从磁盘文件中输入数据,将数据输出到磁盘文件中。简称文件将数据输出到磁盘文件中。简称文件I/Ou对内存中指定的空间进行输入输出。通常指定一个字符数组作为对内存中指定的空间进行输入输出。通常指定一个字符数组作为存储空间,它称为字符串输入输出,简称串

40、存储空间,它称为字符串输入输出,简称串I/OC+采取了不同的方法,实现这三种输入输出。采取了不同的方法,实现这三种输入输出。C+ 6- 30 7.1 C+的输入和输出的输入和输出lC+输入输出流输入输出流C+的输入输出流是指由若干字节组成的字节序列。在的输入输出流是指由若干字节组成的字节序列。在内存中,系统为每一个数据流开辟一个缓冲区,用来存放流内存中,系统为每一个数据流开辟一个缓冲区,用来存放流中的数据。中的数据。u当使用当使用 cout 和插入符和插入符“”从输入缓冲区提取数据,从输入缓冲区提取数据,送给程序中的相关变量。送给程序中的相关变量。总之,内存缓冲区中的数据就是流。总之,内存缓冲

41、区中的数据就是流。C+ 6- 31 7.1 C+的输入和输出的输入和输出l流类与流对象流类与流对象:在:在C+中,输入输出流被定义成类,中,输入输出流被定义成类,C+的的 I/O 库中的类称为流类库中的类称为流类( stream class )。用流类定义的对象。用流类定义的对象称为流对象。称为流对象。cout 和和 cin 并不是并不是C+提供的语句,它们是提供的语句,它们是iostream类的对象。正如类的对象。正如C+没有提供赋值语句,只提供了赋值表达没有提供赋值语句,只提供了赋值表达式(表达式后面加分号,形成语句)。式(表达式后面加分号,形成语句)。在在 iostream 头文件中重载

42、运算符:头文件中重载运算符:“”在在C+中是位移运算符,由于在中是位移运算符,由于在 iostream 头文件中对它们进头文件中对它们进行了重载,使它们能用做标准输入输出运算符,所以,在用行了重载,使它们能用做标准输入输出运算符,所以,在用它们的程序中必须使用它们的程序中必须使用 #include 语句把语句把iostream类包含到程序中。类包含到程序中。下面我们来看看下面我们来看看 I/O 类库中类的情况。类库中类的情况。C+ 6- 32 7.1 C+的输入和输出的输入和输出lI/O 类库中常用的流类类库中常用的流类 strstreamstrstreamstrstream输入字符串流入字符

43、串流类输出字符串流出字符串流类输入入输出字符串流出字符串流类istrstreamostrstreamstrstreamfstreamfstreamfstream输入文件流入文件流类输出文件流出文件流类输入入输出文件流出文件流类ifstreamofstreamfstreamiostreamiostreamiostream通用通用输入流和其他入流和其他输入流的基入流的基类通用通用输出流和其他出流和其他输出流的基出流的基类通用通用输入入输出流和其他出流和其他输入入输出流的基出流的基类istreamostreamiostreamIostream抽象基抽象基类ios在哪个在哪个头文件中声明文件中声明作作

44、 用用类 名名C+ 6- 33 7.1 C+的输入和输出的输入和输出liostream 文件中定义的文件中定义的4种流对象种流对象stderrostream_withassign屏幕屏幕标准准错误流流clogstderrostream_withassign屏幕屏幕标准准错误流流cerrstdoutostream_withassign屏幕屏幕标准准输出出流流coutstdinistream_withassign键盘标准准输入入流流cinC语言言对应文件文件对应的的类对应设备含含义对象象说明说明n cin 是是 istream 的派生类的派生类 istream_withassign 的对象,它是从

45、键盘输入的对象,它是从键盘输入数据流到内存;数据流到内存;n cout 是是 ostream 的派生类的派生类 ostream_withassign 的对象,它从内存输的对象,它从内存输出数据流到显示器;出数据流到显示器;n cerr 和和 clog 相似,均为向显示器输出出错信息相似,均为向显示器输出出错信息 C+ 6- 34 7.2 标准输出流标准输出流II.clog 流对象流对象:也是标准出错流,是:也是标准出错流,是console log 的缩写。的缩写。作用和作用和 cerr 相同。区别在于,相同。区别在于,cerr 不经过缓冲区,直接不经过缓冲区,直接向显示器输出,而向显示器输出,

46、而 clog 经过缓冲区,缓冲区装满后或遇经过缓冲区,缓冲区装满后或遇到到endl 时,向显示器输出。时,向显示器输出。 #include #include void main( ) float a,b,c,disc; cout abc; if (a=0) cerr a is equal to zero,error!endl; else if (disc=b*b-4*a*c)0) cerr disc=b*b-4*a*c 0 endl; else coutx1=(-b+sqrt(disc)/(2*a)endl; coutx2=(-b-sqrt(disc)/(2*a)endl; C+ 6- 35

47、7.2 标准输出流标准输出流l格式输出格式输出:输出数据时,为简便起见往往不指定输出格式。但也可以:输出数据时,为简便起见往往不指定输出格式。但也可以指定输出格式。指定输出格式。输出格式有两种方法:输出格式有两种方法: 使用控制符输出格式;使用控制符输出格式; 使用流对使用流对象的有关成员函数。象的有关成员函数。u使用控制符输出格式使用控制符输出格式:这些控制符是在头文件:这些控制符是在头文件 iomanip中定义。程序中定义。程序必须包含该头文件。必须包含该头文件。控控 制制 符符作作 用用dec, hex, oct分别设置整数的基数为分别设置整数的基数为10、16、8setbase (n)

48、设置整数基数为设置整数基数为n ( n 为为10,16,8三者之一三者之一)setfill ( c ) 设置填充字符设置填充字符c,c是字符常量或变量是字符常量或变量setprecision (n)设置实数精度为设置实数精度为n位位setw (n)设置字段宽度为设置字段宽度为 nsetiosflags (ios:left / right )输出数据左输出数据左/右对齐右对齐resetioflags ( )终止已设置的输出格式,在括号中指定内容终止已设置的输出格式,在括号中指定内容C+ 6- 36 7.2 标准输出流标准输出流#include #include int main( ) int a

49、=123; char *pt = “China”; double pi = 22.0/7.0; cout “dec:”decaendl; cout “hec:”hexaendl; cout “oct:”octaendl; coutsetw(10)ptendl; coutsetfill(*)setw(10)ptendl; cout“pi=”piendl; cout“pi=“setprecision(4)piendl; cout“pi=“setiosflags (ios:fixed) piendl; return 0;C+ 6- 37 7.2 标准输出流标准输出流l用流成员函数用流成员函数 put

50、 输出字符输出字符我们已经知道,程序中一般用我们已经知道,程序中一般用 cout 实现输出,实现输出,cout 流在内存中有相应的缓冲区。流在内存中有相应的缓冲区。有时,我们想只输出一个字符,有时,我们想只输出一个字符,ostream 类提供了类提供了 put 成员函数来满足这一特殊需求:成员函数来满足这一特殊需求:#include int main( ) char *a = BASIC; for (int i=4; i=0; i-) cout.put(*(a+i); cout.put(n); return 0;C+ 6- 38 7.3 标准输入流标准输入流lcin 流流:cin 流是流是 i

51、stream类的对象。它从标准输入设备(键盘)获取数类的对象。它从标准输入设备(键盘)获取数据,程序中的变量通过流提取符据,程序中的变量通过流提取符“”从流中提取数据。从流中提取数据。l用于字符输入的流成员函数:用于字符输入的流成员函数:用用get 函数读入一个字符:函数读入一个字符:get函数有三中函数有三中形式:无参数、有一个参数和形式:无参数、有一个参数和3个参数的形式。个参数的形式。u不带参数的不带参数的 get 函数函数:其调用形式为:其调用形式为:cin.get ( )#include int main( ) char c; cout“input a sentence,please

52、: endl; while (c=cin.get()!=EOF) coutc; return 0;C+ 6- 39 7.3 标准输入流标准输入流u有一个参数的有一个参数的get函数:调用形式为:函数:调用形式为:cin.get(ch)。作用。作用是从输入流中读取一个字符,并赋给变量是从输入流中读取一个字符,并赋给变量 ch 。#include int main( ) char c; coutinpute a sectence,please: endl; while (cin.get(c) cout.put(c); coutendendl; return 0;C+ 6- 40 7.3 标准输入流

53、标准输入流u有三个参数的有三个参数的 get 函数:调用形式:函数:调用形式: cin.get ( 字符数组字符数组/字符指针,字符个数字符指针,字符个数n,终止字符,终止字符)其作用是,从输入流中读取其作用是,从输入流中读取 n-1 个字符,并赋给指定的数个字符,并赋给指定的数组(或指针指向的数组)。如果在读取中遇见终止字符,则提组(或指针指向的数组)。如果在读取中遇见终止字符,则提前结束读取操作。前结束读取操作。#include int main( ) char ch20; coutinpute a sectence,please: endl; cin.get(ch,18,n); cout

54、chendl; return 0;C+ 6- 41 7.3 标准输入流标准输入流l用成员函数用成员函数getline 读入一行字符。调用形式:读入一行字符。调用形式: getline ( 字符数组字符数组/字符指针字符指针, 字符个数字符个数n, 终止字符终止字符 )作用是从读入流中读取一行字符,并赋给字符数组。作用是从读入流中读取一行字符,并赋给字符数组。C+ 6- 42 7.3 标准输入流标准输入流listream 类其它成员函数类其它成员函数ueof 函数函数:表示文件结束。从输入流中读入文件,当达到:表示文件结束。从输入流中读入文件,当达到文件尾,则文件尾,则eof函数值为非函数值为非

55、0(表示真),否则为(表示真),否则为0 (假假)。#include int main( ) char c; while (!cin.eof() if (c=cin.get()!= ) cout.put(c); else cout.put(_); return 0;C+ 6- 43 7.4 文件操作与文件流文件操作与文件流l文件的概念文件的概念:文件一般是指存储在外部介质上的数据集合。:文件一般是指存储在外部介质上的数据集合。我们主要是指数据文件。根据数据的组织形式,数据文件分我们主要是指数据文件。根据数据的组织形式,数据文件分为:为:uASCII文件文件:又称为文本文件,它的每一个字节放一个

56、:又称为文本文件,它的每一个字节放一个ASCII代码,代表一个字符。代码,代表一个字符。u二进制文件二进制文件:又称为内部格式文件,它把数据按其在内存:又称为内部格式文件,它把数据按其在内存中的存储形式远洋输出到磁盘上存放。中的存储形式远洋输出到磁盘上存放。对于字符信息,在内存中是以对于字符信息,在内存中是以ASCII代码形式存放的,代码形式存放的,因此,无论用因此,无论用ASCII文件输出,还是用二进制文件输出,其文件输出,还是用二进制文件输出,其数据形式是一样的。但是对于数值数据,二者是不同的。数据形式是一样的。但是对于数值数据,二者是不同的。C+ 6- 44 7.4 文件操作与文件流文件

57、操作与文件流l文件流类与文件流对象文件流类与文件流对象:文件流是以外存文件为输入输出对象的:文件流是以外存文件为输入输出对象的数据流。数据流。u输出文件流输出文件流是从内存流向外存文件的数据;是从内存流向外存文件的数据;u输入文件流输入文件流是从外存文件流向内存的数据。是从外存文件流向内存的数据。u文件与文件流的区别文件与文件流的区别:文件流不是文件,而只是以文件为输入:文件流不是文件,而只是以文件为输入输出对象的流。输出对象的流。uC+定义的文件类定义的文件类:n ifstream 类,是类,是 istream 类派生,用于从磁盘文件输入数类派生,用于从磁盘文件输入数据。据。n ofstre

58、am 是是ostream 类派生,用于向磁盘文件的输出。类派生,用于向磁盘文件的输出。n fstream 是是 iostream 类的派生,用于磁盘文件的输入输出。类的派生,用于磁盘文件的输入输出。C+ 6- 45 7.4 文件操作与文件流文件操作与文件流l文件的打开与关闭文件的打开与关闭u打开磁盘文件打开磁盘文件:打开文件是指在文件读写之前做必要的准备工:打开文件是指在文件读写之前做必要的准备工作。包括:作。包括:n 为文件对象和指定的磁盘文件建立关联,以便使文件流流向为文件对象和指定的磁盘文件建立关联,以便使文件流流向指定的磁盘文件;指定的磁盘文件;n 指定文件的工作方式,如,是读文件还是

59、写文件,是操作指定文件的工作方式,如,是读文件还是写文件,是操作ASCII文件还是二进制文件。文件还是二进制文件。打开文件有两种实现方式:打开文件有两种实现方式:u调用文件流的成员函数调用文件流的成员函数open。一般形式为:。一般形式为:文件流对象文件流对象.open ( 磁盘文件名,磁盘文件名, 输入输出方式输入输出方式 );注意,磁盘文件名可以包括路径,省略路径则默认为当前目注意,磁盘文件名可以包括路径,省略路径则默认为当前目录。如:录。如: ofstream outfile; / 定义定义ofstream 类对象类对象 outfile outfile.open (“fi.dat, io

60、s:out ); / 使文件流与使文件流与f1.dat文件建立关联文件建立关联C+ 6- 46 7.4 文件操作与文件流文件操作与文件流u在定义文件流对象时指定参数:比如在定义文件流对象时指定参数:比如ostream outfile (“f1.dat”, ios:out );一般常用这种形式来打开文件。一般常用这种形式来打开文件。C+ 6- 47 7.4 文件操作与文件流文件操作与文件流l文件的输入输出方式设置值:文件的输入输出方式设置值:方式方式作用作用ios : in以输入方式打开文件以输入方式打开文件ios : out以输出方式打开文件。若文件存在,则清除原内容以输出方式打开文件。若文件

61、存在,则清除原内容ios : app以输出方式打开文件。写入的数据增加在文件末尾以输出方式打开文件。写入的数据增加在文件末尾ios : ate打开已有文件,文件指针指向文件末尾打开已有文件,文件指针指向文件末尾ios : trunc打开文件,若文件存在,则删除原数据打开文件,若文件存在,则删除原数据ios : binary以二进制方式打开文件以二进制方式打开文件ios : in | ios : out以读写方式打开文件以读写方式打开文件ios : out | ios : binary以二进制方式打开输出文件以二进制方式打开输出文件ios : in | ios : binar以二进制方式打开输入

62、文件以二进制方式打开输入文件C+ 6- 48 7.4 文件操作与文件流文件操作与文件流l关闭磁盘文件关闭磁盘文件:即解除该磁盘文件与文件流的关联。关闭文:即解除该磁盘文件与文件流的关联。关闭文件的成员函数:件的成员函数:outfile.close ( ); C+ 6- 49 7.5 字符串流字符串流l字符串流的概念字符串流的概念:文件流是以外存文件为输入输出对象的数:文件流是以外存文件为输入输出对象的数据流,而字符串流是将数据输出到内存中的字符数组,或从据流,而字符串流是将数据输出到内存中的字符数组,或从字符数组读入数据。字符串流也称内存流。字符数组读入数据。字符串流也称内存流。l字符串流缓冲

63、区字符串流缓冲区:字符串流也有缓冲区。一开始,缓冲区为:字符串流也有缓冲区。一开始,缓冲区为空。空。u如果向字符数组存入数据,随着向流插入数据,流缓冲区如果向字符数组存入数据,随着向流插入数据,流缓冲区中的数据不断增加。当缓冲区满或遇到换行符,缓冲区内中的数据不断增加。当缓冲区满或遇到换行符,缓冲区内容变全部存入字符数组。容变全部存入字符数组。u如果是从字符数组读数据,先将字符数组中的数据送到缓如果是从字符数组读数据,先将字符数组中的数据送到缓冲区,然后从缓冲区提取数据赋给有关变量。冲区,然后从缓冲区提取数据赋给有关变量。C+ 6- 50 7.5 字符串流字符串流数据存入字符数组之前,先要将数

64、据转换成数据存入字符数组之前,先要将数据转换成ASCII代码,代码,然后放入缓冲区,再从缓冲区送到字符数组。然后放入缓冲区,再从缓冲区送到字符数组。字符串流类的类型有:字符串流类的类型有:uIstrstream 类;类;uOstrstream 类;类;uStrstream 类。类。文件流类和字符串流类都是文件流类和字符串流类都是ostream类、类、istream类和类和iostream 类的派生类。类的派生类。C+ 6- 51 7.5 字符串流字符串流l建立输出字符串流对象建立输出字符串流对象:ostrstream 类提供的构造函数原型类提供的构造函数原型为:为: ostrstream :

65、ostrstream (char *buffer, int n, int mode=ios:out );其中:其中:ubuffer是指向字符数组首元素的指针;是指向字符数组首元素的指针;un 为指定的流缓冲区大小,一般与字符数组大小相同;为指定的流缓冲区大小,一般与字符数组大小相同;u第三个参数可选,默认为第三个参数可选,默认为ios:;out方式,可以用以下语句方式,可以用以下语句建立输出字符串流对象并与字符数组建立关联:建立输出字符串流对象并与字符数组建立关联:ostrstream strout (ch1,20);作用是建立输出字符串流对象作用是建立输出字符串流对象 strout 与字符数

66、组与字符数组ch1关联,缓冲区大小为关联,缓冲区大小为20。C+ 6- 52 7.5 字符串流字符串流l建立输入输出字符串流对象:建立输入输出字符串流对象:strstream 类提供的构造函数类提供的构造函数原型为:原型为:strstream : strstream (char *buffer, int n, int mode );可以用以下语句建立输入输出字符流对象:可以用以下语句建立输入输出字符流对象:strstream strio (ch3, sizeof(ch3),ios:in|ios:out);作用是建立输入输出字符串流对象,以字符数组作用是建立输入输出字符串流对象,以字符数组ch3

67、为输入为输入输出对象,流缓冲区大小与输出对象,流缓冲区大小与ch3相同。相同。C+ 6- 53 7.5 字符串流字符串流例:将三个学生数据保存在字符数组中。例:将三个学生数据保存在字符数组中。#include #include using namespace std;struct student int num; char name10; int score;void main()student stud3= 1001,Li,78,1002,Liu,98,1003,Ge,90; char c50; ostrstream strout (c,30); for (int i=0;i3;i+) st

68、routstudi.numstudi.namestudi.score; stroutends; coutarray c:cendl; Object-OrientedProgramminginC+第八章C+工具C+ 6- 55 8.1 命名空间命名空间8.2 使用早期的函数库使用早期的函数库C+ 6- 56 8.1 命名空间命名空间本课程的各章节的程序中,都用到了这样的语句:本课程的各章节的程序中,都用到了这样的语句:using namespac std;这就是命名空间这就是命名空间std。l为什么需要命名空间?为什么需要命名空间?C语言定义了语言定义了3个作用域,即文件域,个作用域,即文件域,

69、函数域和复合语句域。函数域和复合语句域。C+又引入了类作用域。又引入了类作用域。不同的作用域中可以用相同的变量名,互不干扰。但是,不同的作用域中可以用相同的变量名,互不干扰。但是,如果是在不同的库文件如果是在不同的库文件( *.h )中,有相同的变量名和类名,而中,有相同的变量名和类名,而不巧又在被一个程序包含、主文件中又调用了该变量,定义不巧又在被一个程序包含、主文件中又调用了该变量,定义了该类对象,于是引起矛盾冲突。了该类对象,于是引起矛盾冲突。C+ 6- 57 8.1 命名空间命名空间l什么是命名空间?什么是命名空间?为了解决这个问题,为了解决这个问题,ANSI C+增加了命名增加了命名

70、空间的概念。简单地说,就是空间的概念。简单地说,就是ANSI C+引入的,可以由用引入的,可以由用户命名的内存区域,把一些全局实体分别放在各个命名空间户命名的内存区域,把一些全局实体分别放在各个命名空间中,从而与其他全局实体分隔开来。比如:中,从而与其他全局实体分隔开来。比如:namespace nsl int a; double b;其中:其中:unamespace 是定义命名空间的关键字;是定义命名空间的关键字;unsl 是用户指定的空间名。是用户指定的空间名。u花括号内包含的花括号内包含的a,b,是命名空间成员。,是命名空间成员。C+ 6- 58 8.1 命名空间命名空间注意注意a 和和

71、b 仍然是全局变量,仅仅把它们隐藏在命名空仍然是全局变量,仅仅把它们隐藏在命名空间中,而程序中如果要使用变量间中,而程序中如果要使用变量a 和和b,必须加上空间名和,必须加上空间名和域分辨符。如:域分辨符。如:nsl:a,nsl:b 等。这些名字称为等。这些名字称为被限定名被限定名。C+中的命名空间和被限定名的关系,类似与操作系统中的命名空间和被限定名的关系,类似与操作系统中文件夹和其中文件的关系。中文件夹和其中文件的关系。l命名空间的作用命名空间的作用:是建立一些互相分隔的作用域,把一些:是建立一些互相分隔的作用域,把一些全局实体分割开来,以免产生名字冲突。命名空间中的被全局实体分割开来,以

72、免产生名字冲突。命名空间中的被限定名可以是:限定名可以是:u常量和变量常量和变量( 可以带有初始化可以带有初始化 );u函数函数( 可以是定义或声明可以是定义或声明 );u结构体或类;结构体或类;u模板或另一个命名空间模板或另一个命名空间( 意味着,命名空间可以嵌套意味着,命名空间可以嵌套 )C+ 6- 59 8.1 命名空间命名空间l使用命名空间解决名字冲突使用命名空间解决名字冲突:我们举例说明如何解决冲突。:我们举例说明如何解决冲突。/ header1.h#include #include using namespace std;namespace ns1 / 声明命名空间声明命名空间ns

73、1 class student / 在在ns1中声明学生类中声明学生类 public: student (int n, string nam, int a) num=n; name=nam; age=a; void get_data( ); private: int num; string name; int age; ; void student:get_data() coutnum“ “name “ageendl; double fun (double a, double b) / 在在ns1中定义中定义fun函数函数 return sqrt(a+b); / header2.h#inclu

74、de #include using namespace std;namespace ns2 / 声明命名空间声明命名空间ns2 class student / 在在ns2中声明学生类中声明学生类 public: student (int n, string nam, char s ) num=n; name=nam; sex=s; void get_data( ); private: int num; char name20; int age; ; void student:get_data() coutnum“ “name “sexendl; double fun (double a, do

75、uble b) / 在在ns2中定义中定义fun函数函数 return sqrt(a-b); C+ 6- 60 8.1 命名空间命名空间l两个头文件中有相同名字的类两个头文件中有相同名字的类和函数,分别放在不同的命和函数,分别放在不同的命名空间中,避免冲突。名空间中,避免冲突。l定义对象时,要使用:定义对象时,要使用:空间明空间明:类名类名 对象名对象名(参数表参数表) 的形式来定义对象。的形式来定义对象。l定义好的对象不在命名空间中,定义好的对象不在命名空间中,而在而在main 函数的范围里,所函数的范围里,所以使用对象时,不能加空间以使用对象时,不能加空间的名字!的名字!/ main fi

76、le#include #include “header1.h”#include “header2.h”using namespace std;int main( ) nsl:student stud1(101,”Wang”,18); stud1.get_data( ); / 不要写成不要写成ns1:stud1.get_data( ) coutns1:fun(5,3)endl; ns2:student stud2(102,”Li”,f); stud2.get_data( ); coutns2:fun(5,3)endl; return 0;C+ 6- 61 8.1 命名空间命名空间l使用命名空间的

77、简化形式使用命名空间的简化形式:如果在一个命名空间中定义了至少:如果在一个命名空间中定义了至少10个实体,个实体,就需要至少使用就需要至少使用10次次 using 命名空间名。能否简化呢?可以。命名空间名。能否简化呢?可以。C+提供提供 using namespace 语句来实现简化。其一般形式为:语句来实现简化。其一般形式为: using namespace 命名空间名;命名空间名;例如,例如, using namespace ns1; 声明了在本作用域中要用到命名空间声明了在本作用域中要用到命名空间ns1 中的成员,在使用该命名空间中的成员,在使用该命名空间的任何成员时,都不必使用的任何成

78、员时,都不必使用 ns1 空间名来限定。好象全局对象一样。如空间名来限定。好象全局对象一样。如果紧接上面的声明,有如下语句:果紧接上面的声明,有如下语句: student stud1(101, “Wang”,18);则是指定义一个则是指定义一个ns1空间中的空间中的 student 类对象。类对象。C+ 6- 62 8.1 命名空间命名空间l无名的命名空间无名的命名空间:C+允许使用没有名字的命名空间,如:允许使用没有名字的命名空间,如: namespace void fun( ) cout“OK!”endl; 这种无名的名字空间在其他文件中无法引用,只能在本这种无名的名字空间在其他文件中无法

79、引用,只能在本文件的作用域内有效。无名空间中的成员,如上面提到的函文件的作用域内有效。无名空间中的成员,如上面提到的函数数 fun 的作用域是从定义位置开始到文件结束的范围。的作用域是从定义位置开始到文件结束的范围。C+ 6- 63 8.1 命名空间命名空间l标准命名空间标准命名空间 std :为了解决:为了解决C+标准库中的标识符与程序标准库中的标识符与程序中的全局标识符之间,以及不同库之间的同名冲突,应该将中的全局标识符之间,以及不同库之间的同名冲突,应该将不同库的标识符在不同的命名空间中定义。不同库的标识符在不同的命名空间中定义。标准标准C+库的所有标识符都是在一个名为库的所有标识符都是

80、在一个名为 std 命名空间命名空间中定义的。或者说,标准头文件中定义的。或者说,标准头文件( 如如 stream)中的函数、类、中的函数、类、对象和类模板是在命名空间对象和类模板是在命名空间 std 中定义的。中定义的。这样,在程序中用到这样,在程序中用到C+标准库的被限定成员时,如:标准库的被限定成员时,如: std:cout“OK.”endl;在程序头一般要加上在程序头一般要加上 using namespace std;每当用到每当用到std 命名空间中的被限定成员时,就可省略命名空间中的被限定成员时,就可省略std: 限定语。如:限定语。如:cout“OK.”endl;C+ 6- 64

81、 8.2 使用早期的函数库使用早期的函数库在在C语言的发展过程中,产生了丰富的函数库。语言的发展过程中,产生了丰富的函数库。C+可可以使用这些函数库。要使用它们,就必须在程序中包含相关以使用这些函数库。要使用它们,就必须在程序中包含相关的头文件。的头文件。C+使用这些头文件有两种方法:使用这些头文件有两种方法:l用用C语言的传统方法语言的传统方法。头文件名包括后缀。头文件名包括后缀.h,如,如 stdio.h、 math.h 等,由于等,由于C语言没有命名空间,头文件并不存放在命语言没有命名空间,头文件并不存放在命名空间中,因此在名空间中,因此在C+程序文件中如果用到带程序文件中如果用到带.h

82、 后缀的头文后缀的头文件时,不必使用命名空间,只需要包含要用到的头文件名就件时,不必使用命名空间,只需要包含要用到的头文件名就行。如:行。如:#include C+ 6- 65 8.2 使用早期的函数库使用早期的函数库l用用C+的新方法的新方法:C+标准要求系统提供的头文件不包括后标准要求系统提供的头文件不包括后缀缀.h 。例如,。例如,iostream, string 。为了区别于。为了区别于C语言的头文语言的头文件,件,C+头文件相应的文件名之前都加一字母头文件相应的文件名之前都加一字母 c 。例如,。例如,C语言的语言的 stdio.h 文件,文件,C+中改名为中改名为 cstdio。C语言中的语言中的string.h 头文件,头文件,C+中改名为中改名为 cstring 。并且后者增加了。并且后者增加了很多内容,不是同一个文件。很多内容,不是同一个文件。此外,由于这些函数都是在命名空间此外,由于这些函数都是在命名空间 std 中声明的,因中声明的,因此在程序中要对命名空间此在程序中要对命名空间 std 作声明。比如:作声明。比如:#include #include using namespace std;

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 资格认证/考试 > 自考

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号