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

上传人:牧羊曲112 文档编号:6213418 上传时间:2023-10-05 格式:PPT 页数:66 大小:875.51KB
返回 下载 相关 举报
面向对象程序设计之多态性与虚函数.ppt_第1页
第1页 / 共66页
面向对象程序设计之多态性与虚函数.ppt_第2页
第2页 / 共66页
面向对象程序设计之多态性与虚函数.ppt_第3页
第3页 / 共66页
面向对象程序设计之多态性与虚函数.ppt_第4页
第4页 / 共66页
面向对象程序设计之多态性与虚函数.ppt_第5页
第5页 / 共66页
点击查看更多>>
资源描述

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

1、Object-OrientedProgramming in C+第六章 多态性与虚函数,6.1 多态性的概念,多态性(polymorphism)是面向对象程序设计的重要特征。一个算法语言如果只支持类,而不支持多态,只能说是基于对象的语言,如Ada,VB。C+支持多态性,在C+程序设计中能够实现多态性。利用多态性,可以设计和扩展一个易于扩展的系统。什么叫多态?多态的意思是一种事物的多种形态。在C+中,是指具有不同功能的函数可以用同一个函数名。面向对象方法中一般是这样描述多态性的:向不同的对象发送同一个消息,不同的对象在接收时会产生不同的行为(即方法)。,写出程序运行结果,#include#inc

2、lude Using namespace std;class studentpublic: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

3、),void display()coutdisplay();pt=,6.1 多态性的概念,我们其实已经接触过多态性的现象。如函数的重载多态性分类:从系统实现的角度看,多态性分为以下两类:静态多态性:又称编译时的多态性。如函数重载属于静态多态性。动态多态性:有称为运行时的多态性。它主要表现为虚函数(virtual function)。,6.3 虚函数,能否用一个调用形式,既能调用派生类的函数,又能调用基类同名函数?C+中的虚函数就是用来解决这一问题。虚函数的作用:虚函数的作用是允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数。,6.3 虚函数,#i

4、nclude#include class studentpublic: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 dis

5、play()coutdisplay();/指向基类对象s1 pt=/指向派生类对象g1,仅输出了派生类的基类数据成员,因为它调用的是基类成员函数display!,假如想输出派生类的全部数据,当然可以采用下面两种方法之一:通过派生类对象名g1,调用派生类对象的成员函数:g1.display();定义一个指向派生类的指针ptr,并指向g1,然后用ptr-display()。,6.3 虚函数,我们可以用虚函数可以顺利解决这一问题。方法是:在基类student 中声明 display函数时,在最左边加上一个关键字virtual:virtual void display();就可以student类的di

6、splay函数声明为虚函数,程序其它部分不变编译运行后,可见,使用pt-display(),的确将graduate类对象 g1 的全部数据显示了出来,说明它调用的是g1 的成员函数 display。在派生类中重新定义该函数,要求函数名、函数类型、参数表完全相同。但不加virtual关键字。只在类里的成员函数声明时,加上关键字virtual,在类外定义定义虚函数时,不加virtual关键字。定义一个指向基类对象的指针,并使她指向同一类中的某一对象;通过该指针标量调用此虚函数,此时调用的就是指针变量指向的对象的同名函数,而不是基类的同名函数!,6.3 虚函数,通过使用虚函数和指针,就能方便地调用同

7、一类族中不同类对象的同名函数,只要先用基类指针指向该对象即可。,#include#include class studentpublic:student(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

8、,float p):student(n,nam,s),pay(p),void display()coutdisplay();/指向基类对象s1 pt=/指向派生类对象g1,调用g1的显示函数display,打印出g1全部数据成员,6.3 虚函数,将函数重载与虚函数比较,可见:函数重载是解决的是同一层次上的同名函数的问题。是横向重载。虚函数解决的是不同派生层次上的同名函数的问题。相当于纵向重载。同一类族的虚函数的首部是相同的;而重载函数的首部不相同(参数表不能相同)。,6.3 虚函数,静态关联与动态关联C+在编译或运行时,对多个同名函数究竟调用哪一个函数,需要一定的机制来确定。这种确定调用的具体

9、对象的过程称为“关联(binding)”,即把函数名与某一个类对象捆绑在一起。函数重载,在编译时就可确定其调用的函数是哪一个;通过对象名调用虚函数,在编译时也可确定其调用的虚函数属于哪一个类。其过程称为“静态关联(static binding),因为是在运行前进行关联的,又成为早期关联(early binding)。,6.3 虚函数,通过指针和虚函数的结合,在编译阶段是没法进行关联的,因为编译只作静态的语法检查,光从语句形式pt-display()无法确定调用的对象,也就没法关联。出现这种情况,我们可以在运行阶段来处理关联。在运行阶段,基类指针先指向某一个对象,然后通过指针调用该对象的成员函数

10、。此时调用哪个函数是确定的,没有不确定因素。例如语句 pt=非常确定的是调用g1对象的成员函数display。这种情况由于是在运行阶段将虚函数与某一类对象“绑定”在一起的,因此称为“动态关联(dynamic binding),或“滞后关联(late binding)”。,6.3 虚函数,使用虚函数,要注意只能用virtual 声明类的成员函数,类外的普通函数不能声明成虚函数,因为它没有继承的操作。一个成员函数被声明成虚函数后,在同一类族中的类就不能再定义一个非virtual的、但与该函数具有相同参数表和返回类型的同名函数。使用虚函数,系统要有一定的空间开销。当一个类带有虚函数时,编译系统会为该

11、类构造一个虚函数表(virtual function table,vtable),它是一个指针数组,存放每个虚函数的入口地址。系统在进行动态关联时的时间开销是很少的,所以多态性运行效率非常高。,6.3 虚函数,什么情况下使用虚函数?成员函数所在的类是否会作为基类?成员函数被继承后有没有可能发生功能变化,如果两个因素都具备,就应该将它声明成虚函数。如果成员函数被继承后功能不变,或派生类用不到该函数,就不要声明成虚函数。应考虑对成员函数的访问是通过对象名还是基类指针,如果是通过基类指针或引用访问,则应当声明为虚函数。有时基类中定义虚函数时并不定义它的函数体,即函数体为空。其作用只是定义了一个虚函数

12、名,具体功能留给派生类添加(6.4 节会讨论这种情况)。,6.3 虚函数,虚析构函数问题的引出:我们知道,当派生类对象撤消时,系统先调用派生类析构函数,再调用基类析构函数。但是,如果用new 运算符建立了一个派生类临时对象,但用一个基类指针指向它,当程序用带指针参数的delete 撤消对象时,会发生让人不能接受的情况:系统只析构基类对象,而不析构派生类对象:,class pointpublic:point()point()cout“析构基类对象”endl;class circle:public pointpublic:circle()circle()cout“析构派生类对象”endl;,pri

13、vate:int radius;int main()point*p=new circle;/指针为指向基类对象指针,/但实际指向临时派生类对象 delete p;return 0;,6.3 虚函数,实际上,程序只析构了基类对象,而没有析构派生类对象,为什么呢?因为指针p 为基类指针,系统认为它只有基类对象,而与派生类对象无关。实际上,由于该指针被指向了一个临时派生类对象,所以还应该这个临时的析构派生类对象。解决的办法:可以将基类的析构函数声明为虚析构函数。如:virtual point()cout“析构基类对象”endl;程序其它部分不动,就行了。当基类的析构函数被定义成virtual,无论指

14、针指向同一类族中的哪一个对象,当撤消对象时,系统会采用动态关联,调用相应的析构函数,清理该对象,然后再析构基类对象。,6.4 纯虚函数与抽象类,前面已经提到,有时在基类中将某一成员函数定为虚函数并不是基类本身的需要,而是派生类的需要。在基类中预留一个函数名,具体功能留给派生类根据需要去定义。在上一节中基类point 中有定义面积area函数,是因为“点”没有面积的概念。但是,其直接派生类circle和间接派生类cylinder却都需要area 函数,而且这两个area 函数的功能还不相同,一个是求圆面积,一个是求圆柱体表面积。也许会想到,在基类point 中加一个area 函数,并声明为虚函数

15、:virtual float area()const return 0;其返回0表示“点”没有面积。其实,在基类中并不使用这个函数,其返回值也没有意义。,6.4 纯虚函数与抽象类,为简化起见,可以不写出这种无意义的函数体,只给出函数的原型,并在后面加上“=0”,如:virtual float area()const=0;/纯虚函数这就将area声明为一个纯虚函数(pure virtual function)纯虚函数的声明形式virtual 函数类型 函数名(参数表)=0;说明纯虚函数没有函数体;最后的“=0”不表示函数值返回0,它只是形式上的作用,告诉编译系统:这是纯虚函数,这是一个声明语句,

16、以分号结尾。如果基类中声明了纯虚函数,但派生类中定义该函数,则该虚函数在派生类中仍为纯虚函数。,6.4 纯虚函数与抽象类,纯虚函数的作用是在基类中为其派生类保留一个函数的名字,以便派生类根据需要对它进行定义。如果基类中没有保留函数名,则无法实现多态性。,6.4 纯虚函数与抽象类,抽象类什么叫抽象类?一般声明了一个类,用来定义若干对象。但有些类并不是用来生成对象,而是作为基类去建立派生类。这种不用来定义对象,而只作为一种基本类型用做继承的类,就叫抽象类(abstract class)。由于抽象类常作为基类,我们也称为抽象基类(abstract base class)。比如,凡是包含纯虚函数的类都

17、叫抽象类。因为纯虚函数不能被调用,包含纯虚函数的类无法建立对象。抽象类的作用:是作为一个类族的共同基类。即,为一个类族提供一个公共接口。一个类层次结构中可以不包含任何抽象类,每一层次的类都可以建立对象。但是,许多系统的顶层是一个抽象类,甚至顶部有好几层都是抽象类。,6.4 纯虚函数与抽象类,如果由抽象类所派生出的新类中对基类的所有纯虚函数都进行了定义,这个派生类就不是抽象类,可以被调用,成为可以用来定义对象的具体类(concrete class)。如果由抽象类所派生出的新类中对基类的所有纯虚函数都没有进行定义,这个派生类就仍然是抽象类。虽然抽象类不能定义对象,但可以定义指向抽象类的数据的指针。

18、当派生类成为具体类之后,就可以用这种指针向派生类对象,然后通过该指针调用虚函数,实现多态性操作。,编程练习:定义虚函数,基类为SHAPE,派生出圆形、矩形、三角形类。,#include using namespace std;/定义抽象基类Shapeclass Shapepublic:/定义纯虚函数;/定义Circle类class Circle:public Shapepublic:Circle(double r):radius(r)/定义虚函数 protected:double radius;/半径;,/定义Rectangle类class Rectangle:public Shapepubl

19、ic:Rectangle(double w,double h):width(w),height(h)/定义虚函数 protected:double width,height;class Triangle:public Shapepublic:Triangle(double w,double h):width(w),height(h)/定义虚函数 protected:double width,height;,#include using namespace std;/定义抽象基类Shapeclass Shapepublic:virtual double area()const=0;/纯虚函数;/

20、定义Circle类class Circle:public Shapepublic:Circle(double r):radius(r)virtual double area()const return 3.14159*radius*radius;/定义虚函数 protected:double radius;/半径;,/定义Rectangle类class Rectangle:public Shapepublic:Rectangle(double w,double h):width(w),height(h)virtual double area()const return width*height

21、;/定义虚函数 protected:double width,height;class Triangle:public Shapepublic:Triangle(double w,double h):width(w),height(h)virtual double area()const return 0.5*width*height;/定义虚函数 protected:double width,height;,续:定义一个函数printArea,以对象为形参,输出三种形状的面积,int main()Circle circle(12.6);/建立Circle类对象circle coutarea

22、of circle=;printArea(circle);/输出circle的面积 Rectangle rectangle(4.5,8.4);/建立Rectangle类对象rectangle coutarea of rectangle=;printArea(rectangle);/输出rectangle的面积 Triangle triangle(4.5,8.4);/建立Triangle类对象 coutarea of triangle=;printArea(triangle);/输出triangle的面积 return 0;,/输出面积的函数void printArea(const Shape,

23、6.4 纯虚函数与抽象类,多态性把操作细节留给类的设计者(专业人员)去完成,而让编程人员(类的使用者)只需做一些宏观性的工作,告诉系统做什么,不必考虑怎么做,简化了应用程序的编码工作。因此有人说,多态性是开启继承功能的钥匙。,Object-OrientedProgramming in C+第七章 输入输出流,第一章 C+的初步知识第二章 类和对象第三章 再论类和对象第四章 运算符重载第五章 继承与派生第六章 多态性与虚函数第七章 输入输出流第八章 C+工具,7.1 C+的输入与输出7.2 标准输出流7.3 标准出入流7.4 文件操作与文件流7.5 字符串流,7.1 C+的输入和输出,输入输出的

24、含义:从操作系统角度看,每一个与主机相连的输入输出设备都被看做一个文件。终端键盘是输入文件,终端显示器是输出文件。磁盘或光盘也可以被看作是输入输出文件。程序的输入:指的是从输入文件将数据传送给程序;程序的输出:指的是从程序将数据输出给输出文件。C+的输入输出包括以下三个方面的内容:标准设备输入输出,从键盘输入。输出到显示器。简称标准I/O。以外存储器文件为对象的输入输出。指从磁盘文件中输入数据,将数据输出到磁盘文件中。简称文件I/O对内存中指定的空间进行输入输出。通常指定一个字符数组作为存储空间,它称为字符串输入输出,简称串I/OC+采取了不同的方法,实现这三种输入输出。,7.1 C+的输入和

25、输出,C+输入输出流C+的输入输出流是指由若干字节组成的字节序列。在内存中,系统为每一个数据流开辟一个缓冲区,用来存放流中的数据。当使用 cout 和插入符“”从输入缓冲区提取数据,送给程序中的相关变量。总之,内存缓冲区中的数据就是流。,7.1 C+的输入和输出,流类与流对象:在C+中,输入输出流被定义成类,C+的 I/O 库中的类称为流类(stream class)。用流类定义的对象称为流对象。cout 和 cin 并不是C+提供的语句,它们是iostream类的对象。正如C+没有提供赋值语句,只提供了赋值表达式(表达式后面加分号,形成语句)。在 iostream 头文件中重载运算符:“”在

26、C+中是位移运算符,由于在 iostream 头文件中对它们进行了重载,使它们能用做标准输入输出运算符,所以,在用它们的程序中必须使用#include 语句把iostream类包含到程序中。下面我们来看看 I/O 类库中类的情况。,7.1 C+的输入和输出,I/O 类库中常用的流类,7.1 C+的输入和输出,iostream 文件中定义的4种流对象,说明 cin 是 istream 的派生类 istream_withassign 的对象,它是从键盘输入数据流到内存;cout 是 ostream 的派生类 ostream_withassign 的对象,它从内存输出数据流到显示器;cerr 和 c

27、log 相似,均为向显示器输出出错信息,7.2 标准输出流,clog 流对象:也是标准出错流,是console log 的缩写。作用和 cerr 相同。区别在于,cerr 不经过缓冲区,直接向显示器输出,而 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=(

28、-b+sqrt(disc)/(2*a)endl;coutx2=(-b-sqrt(disc)/(2*a)endl;,7.2 标准输出流,格式输出:输出数据时,为简便起见往往不指定输出格式。但也可以指定输出格式。输出格式有两种方法:使用控制符输出格式;使用流对象的有关成员函数。使用控制符输出格式:这些控制符是在头文件 iomanip中定义。程序必须包含该头文件。,7.2 标准输出流,#include#include int main()int a=123;char*pt=“China”;double pi=22.0/7.0;cout“dec:”decaendl;cout“hec:”hexaendl

29、;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;,7.2 标准输出流,用流成员函数 put 输出字符我们已经知道,程序中一般用 cout 实现输出,cout 流在内存中有相应的缓冲区。有时,我们想只输出一个字符,ostream 类提供了 put 成员函数来满足这一特殊需求:,#include int main()char*

30、a=BASIC;for(int i=4;i=0;i-)cout.put(*(a+i);cout.put(n);return 0;,7.3 标准输入流,cin 流:cin 流是 istream类的对象。它从标准输入设备(键盘)获取数据,程序中的变量通过流提取符“”从流中提取数据。用于字符输入的流成员函数:用get 函数读入一个字符:get函数有三中形式:无参数、有一个参数和3个参数的形式。不带参数的 get 函数:其调用形式为:cin.get(),#include int main()char c;cout“input a sentence,please:endl;while(c=cin.get

31、()!=EOF)coutc;return 0;,7.3 标准输入流,有一个参数的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;,7.3 标准输入流,有三个参数的 get 函数:调用形式:cin.get(字符数组/字符指针,字符个数n,终止字符)其作用是,从输入流中读取 n-1 个字符,并赋给指定的数组(或指针指向的数组)。如果在

32、读取中遇见终止字符,则提前结束读取操作。,#include int main()char ch20;coutinpute a sectence,please:endl;cin.get(ch,18,n);coutchendl;return 0;,7.3 标准输入流,用成员函数getline 读入一行字符。调用形式:getline(字符数组/字符指针,字符个数n,终止字符)作用是从读入流中读取一行字符,并赋给字符数组。,7.3 标准输入流,istream 类其它成员函数eof 函数:表示文件结束。从输入流中读入文件,当达到文件尾,则eof函数值为非0(表示真),否则为0(假)。,#include

33、int main()char c;while(!cin.eof()if(c=cin.get()!=)cout.put(c);else cout.put(_);return 0;,7.4 文件操作与文件流,文件的概念:文件一般是指存储在外部介质上的数据集合。我们主要是指数据文件。根据数据的组织形式,数据文件分为:ASCII文件:又称为文本文件,它的每一个字节放一个ASCII代码,代表一个字符。二进制文件:又称为内部格式文件,它把数据按其在内存中的存储形式远洋输出到磁盘上存放。对于字符信息,在内存中是以ASCII代码形式存放的,因此,无论用ASCII文件输出,还是用二进制文件输出,其数据形式是一样

34、的。但是对于数值数据,二者是不同的。,7.4 文件操作与文件流,文件流类与文件流对象:文件流是以外存文件为输入输出对象的数据流。输出文件流是从内存流向外存文件的数据;输入文件流是从外存文件流向内存的数据。文件与文件流的区别:文件流不是文件,而只是以文件为输入输出对象的流。C+定义的文件类:ifstream 类,是 istream 类派生,用于从磁盘文件输入数据。ofstream 是ostream 类派生,用于向磁盘文件的输出。fstream 是 iostream 类的派生,用于磁盘文件的输入输出。,7.4 文件操作与文件流,文件的打开与关闭打开磁盘文件:打开文件是指在文件读写之前做必要的准备工

35、作。包括:为文件对象和指定的磁盘文件建立关联,以便使文件流流向指定的磁盘文件;指定文件的工作方式,如,是读文件还是写文件,是操作ASCII文件还是二进制文件。打开文件有两种实现方式:调用文件流的成员函数open。一般形式为:文件流对象.open(磁盘文件名,输入输出方式);注意,磁盘文件名可以包括路径,省略路径则默认为当前目录。如:ofstream outfile;/定义ofstream 类对象 outfile outfile.open(“fi.dat,ios:out);/使文件流与f1.dat文件建立关联,7.4 文件操作与文件流,在定义文件流对象时指定参数:比如ostream outfil

36、e(“f1.dat”,ios:out);一般常用这种形式来打开文件。,7.4 文件操作与文件流,文件的输入输出方式设置值:,7.4 文件操作与文件流,关闭磁盘文件:即解除该磁盘文件与文件流的关联。关闭文件的成员函数:outfile.close();,7.5 字符串流,字符串流的概念:文件流是以外存文件为输入输出对象的数据流,而字符串流是将数据输出到内存中的字符数组,或从字符数组读入数据。字符串流也称内存流。字符串流缓冲区:字符串流也有缓冲区。一开始,缓冲区为空。如果向字符数组存入数据,随着向流插入数据,流缓冲区中的数据不断增加。当缓冲区满或遇到换行符,缓冲区内容变全部存入字符数组。如果是从字符

37、数组读数据,先将字符数组中的数据送到缓冲区,然后从缓冲区提取数据赋给有关变量。,7.5 字符串流,数据存入字符数组之前,先要将数据转换成ASCII代码,然后放入缓冲区,再从缓冲区送到字符数组。字符串流类的类型有:Istrstream 类;Ostrstream 类;Strstream 类。文件流类和字符串流类都是ostream类、istream类和iostream 类的派生类。,7.5 字符串流,建立输出字符串流对象:ostrstream 类提供的构造函数原型为:ostrstream:ostrstream(char*buffer,int n,int mode=ios:out);其中:buffer

38、是指向字符数组首元素的指针;n 为指定的流缓冲区大小,一般与字符数组大小相同;第三个参数可选,默认为ios:;out方式,可以用以下语句建立输出字符串流对象并与字符数组建立关联:ostrstream strout(ch1,20);作用是建立输出字符串流对象 strout 与字符数组ch1关联,缓冲区大小为20。,7.5 字符串流,建立输入输出字符串流对象:strstream 类提供的构造函数原型为:strstream:strstream(char*buffer,int n,int mode);可以用以下语句建立输入输出字符流对象:strstream strio(ch3,sizeof(ch3),

39、ios:in|ios:out);作用是建立输入输出字符串流对象,以字符数组ch3为输入输出对象,流缓冲区大小与ch3相同。,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+)stroutstudi.numstu

40、di.namestudi.score;stroutends;coutarray c:cendl;,Object-OrientedProgramming in C+第八章 C+工具,8.1 命名空间8.2 使用早期的函数库,8.1 命名空间,本课程的各章节的程序中,都用到了这样的语句:using namespac std;这就是命名空间std。为什么需要命名空间?C语言定义了3个作用域,即文件域,函数域和复合语句域。C+又引入了类作用域。不同的作用域中可以用相同的变量名,互不干扰。但是,如果是在不同的库文件(*.h)中,有相同的变量名和类名,而不巧又在被一个程序包含、主文件中又调用了该变量,定义

41、了该类对象,于是引起矛盾冲突。,8.1 命名空间,什么是命名空间?为了解决这个问题,ANSI C+增加了命名空间的概念。简单地说,就是ANSI C+引入的,可以由用户命名的内存区域,把一些全局实体分别放在各个命名空间中,从而与其他全局实体分隔开来。比如:namespace nsl int a;double b;其中:namespace 是定义命名空间的关键字;nsl 是用户指定的空间名。花括号内包含的a,b,是命名空间成员。,8.1 命名空间,注意a 和b 仍然是全局变量,仅仅把它们隐藏在命名空间中,而程序中如果要使用变量a 和b,必须加上空间名和域分辨符。如:nsl:a,nsl:b 等。这些

42、名字称为被限定名。C+中的命名空间和被限定名的关系,类似与操作系统中文件夹和其中文件的关系。命名空间的作用:是建立一些互相分隔的作用域,把一些全局实体分割开来,以免产生名字冲突。命名空间中的被限定名可以是:常量和变量(可以带有初始化);函数(可以是定义或声明);结构体或类;模板或另一个命名空间(意味着,命名空间可以嵌套),8.1 命名空间,使用命名空间解决名字冲突:我们举例说明如何解决冲突。,/header1.h#include#include using namespace std;namespace ns1/声明命名空间ns1 class student/在ns1中声明学生类 public

43、: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#include#include using namespace std;namespace ns2/声明命名空间ns2 class student/在ns2中

44、声明学生类 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,double b)/在ns2中定义fun函数 return sqrt(a-b);,8.1 命名空间,两个头文件中有相同名字的类和函数,分别放在不同的命名空间中,避免冲突。定义对象时,要使用:空间明:类名 对象名(参数表)的形式来定义对象

45、。定义好的对象不在命名空间中,而在main 函数的范围里,所以使用对象时,不能加空间的名字!,/main file#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;ret

46、urn 0;,8.1 命名空间,使用命名空间的简化形式:如果在一个命名空间中定义了至少10个实体,就需要至少使用10次 using 命名空间名。能否简化呢?可以。C+提供 using namespace 语句来实现简化。其一般形式为:using namespace 命名空间名;例如,using namespace ns1;声明了在本作用域中要用到命名空间ns1 中的成员,在使用该命名空间的任何成员时,都不必使用 ns1 空间名来限定。好象全局对象一样。如果紧接上面的声明,有如下语句:student stud1(101,“Wang”,18);则是指定义一个ns1空间中的 student 类对象。

47、,8.1 命名空间,无名的命名空间:C+允许使用没有名字的命名空间,如:namespace void fun()cout“OK!”endl;这种无名的名字空间在其他文件中无法引用,只能在本文件的作用域内有效。无名空间中的成员,如上面提到的函数 fun 的作用域是从定义位置开始到文件结束的范围。,8.1 命名空间,标准命名空间 std:为了解决C+标准库中的标识符与程序中的全局标识符之间,以及不同库之间的同名冲突,应该将不同库的标识符在不同的命名空间中定义。标准C+库的所有标识符都是在一个名为 std 命名空间中定义的。或者说,标准头文件(如 stream)中的函数、类、对象和类模板是在命名空间

48、 std 中定义的。这样,在程序中用到C+标准库的被限定成员时,如:std:cout“OK.”endl;在程序头一般要加上 using namespace std;每当用到std 命名空间中的被限定成员时,就可省略std:限定语。如:cout“OK.”endl;,8.2 使用早期的函数库,在C语言的发展过程中,产生了丰富的函数库。C+可以使用这些函数库。要使用它们,就必须在程序中包含相关的头文件。C+使用这些头文件有两种方法:用C语言的传统方法。头文件名包括后缀.h,如 stdio.h、math.h 等,由于C语言没有命名空间,头文件并不存放在命名空间中,因此在C+程序文件中如果用到带.h 后

49、缀的头文件时,不必使用命名空间,只需要包含要用到的头文件名就行。如:#include,8.2 使用早期的函数库,用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备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号