面向对象的程序设计语言ppt课件

上传人:夏** 文档编号:593543444 上传时间:2024-09-25 格式:PPT 页数:171 大小:374KB
返回 下载 相关 举报
面向对象的程序设计语言ppt课件_第1页
第1页 / 共171页
面向对象的程序设计语言ppt课件_第2页
第2页 / 共171页
面向对象的程序设计语言ppt课件_第3页
第3页 / 共171页
面向对象的程序设计语言ppt课件_第4页
第4页 / 共171页
面向对象的程序设计语言ppt课件_第5页
第5页 / 共171页
点击查看更多>>
资源描述

《面向对象的程序设计语言ppt课件》由会员分享,可在线阅读,更多相关《面向对象的程序设计语言ppt课件(171页珍藏版)》请在金锄头文库上搜索。

1、返回返回第三章面向对象的程序设计本章导读本章导读 掌握类与对象的概念,类与对象的定义方法及掌握类与对象的概念,类与对象的定义方法及二者间的区别。二者间的区别。 掌握类的成员函数的定义方法、保管方法及调掌握类的成员函数的定义方法、保管方法及调用方法。掌握类中成员的访问机制和方法。用方法。掌握类中成员的访问机制和方法。 了解对象的作用域和生存期。了解对象的作用域和生存期。 了解并掌握构造函数、析构函数、拷贝构造函了解并掌握构造函数、析构函数、拷贝构造函数、默许构造函数和缺省参数的构造函数的含义、数、默许构造函数和缺省参数的构造函数的含义、定义方法以及在对象的构造和吊销中的作用。定义方法以及在对象的

2、构造和吊销中的作用。 了解并掌握当一个类的对象作为另一个类的数了解并掌握当一个类的对象作为另一个类的数据成员时,利用初始化表调用构造函数的方法、据成员时,利用初始化表调用构造函数的方法、构造函数的执行顺序。构造函数的执行顺序。返回返回本章导读 了解承继的概念和意义,了解单一承继、多重承继。了解并掌握派生类构造函数的编写要求,以及派生类对象的构造过程和机理。 掌握虚函数和多态性的概念,掌握虚函数的定义方法、调用方法及其在实现多态性方面所起到的作用。了解纯虚函数与笼统基类的概念。 了解类的静态成员静态数据成员和静态成员函数的概念、定义方法及其作用。 了解友元函数与友元类的概念、定义方法及其作用。

3、了解运算符重载及在程序中实现运算符重载的方法。 了解模板的概念,在程序中如何定义类模板和函数模板。 返回返回3.1 类与对象的定义类和对象是面向对象程序设计OOP的两个最根本概念。所谓对象就是客观事物在计算机中的笼统描画;类是对具有类似属性和行为的一组对象的一致描画。3.1.1类的定义C+的类是在构造体的根底上扩展而来的。类是把各种不同类型的数据称为数据成员和对数据的操作成员函数组织在一同而构成的用户自定义的数据类型。C+中,类定义包括类阐明和类实现两大部分。阐明部分提供了对该类一切数据成员和成员函数的描画,而实现部分提供了一切成员函数的实现代码。返回返回3.1 类与对象的定义类定义的普通方式

4、为:class类名private:数据成员或成员函数protected:数据成员或成员函数public:数据成员或成员函数;返回返回3.1 类与对象的定义阐明:阐明:1.class是是定定义义类类的的关关键键字字,类类名名由由用用户户本本人人定定名名,必必需需是是C+的有效标识符,但普通首字母大写。的有效标识符,但普通首字母大写。2.大大括括号号的的部部分分是是类类的的成成员员数数据据成成员员和和函函数数成成员员,它它们们分分成成三三部部分分,分分别别由由private、public、proctected三三个个关关键键字字后后跟跟冒冒号号来来指指定定。这这三三部部分分可可以以任任何何顺顺序序

5、出出现现,且在一个类的定义中,这三部分并非必需同时出现。且在一个类的定义中,这三部分并非必需同时出现。1假假设设数数据据成成员员或或成成员员函函数数在在类类的的private部部分分,那那么么在在类类之之外外是是不不能能存存取取的的,只只需需类类中中的的成成员员函函数数才才干干存存取取private的数据成员和成员函数。的数据成员和成员函数。2在在一一个个类类的的public部部分分阐阐明明的的数数据据成成员员或或成成员员函函数数可可被被程程序序中中的的任任何何函函数数或或语语句句存存取取,public成成员员多多为为成成员员函函数数,用用来来提提供供一一个个与与外外界界的的接接口口,外外界界

6、只只需需经经过过这这个个接口才可以实现对接口才可以实现对private成员的存取。成员的存取。返回返回3.1 类与对象的定义3在类的protected部分阐明的数据成员和成员函数是不能在类之外存取的,只需类的成员函数及其子类派生类可以存取protected的成员。4当定义类时,当未指明成员是哪部分时,默许是属于private成员,但普通不要采用默许方式。如:下例中定义描画图书的类定义classRecordprivate:/private成员charbookname20;/数据成员bookname,/用于表示图书的称号intnumber;/数据成员number,表示图书编号返回返回3.1 类与对

7、象的定义public:/public成员voidregist(char*a,intb);/成员函数regist,用于给/各数据成员赋值voidshow();/成员函数show,显示各数据成员的值;要特别留意,在类的定义中,类的阐明部分的右边大括号后面必需有一“;.根据类的定义,可看出:类是实现封装的工具,所谓封装就是将类的成员按运用或存取的方式分类,有条件地限制对类成员的运用,而封装是经过public和private与成员函数实现的。private的成员构成类的内部形状,public的成员那么构成与外界通讯的接口,经过public的成员函数来运用private的数据成员,从而在C+中实现了封装

8、。返回返回3.1 类与对象的定义3.1.2成员函数的定义成员函数的定义类中的成员函数可以在以下两处定义:类中的成员函数可以在以下两处定义:1将成员函数的定义直接写在类中:将成员函数的定义直接写在类中:如如:对对于于前前面面定定义义的的图图书书类类Record来来说说,其其成成员员函函数数regist和和show的定义可直接写在类的定义体中。的定义可直接写在类的定义体中。classRecordprivate:charbookname20;intnumber;返回返回3.1 类与对象的定义public:voidregist(char*a,intb)/成员函数regist()的定义strcpy(bo

9、okname,a);/给数据成员bookname赋值number=b;/给数据成员number赋值voidshow()/成员函数show()的定义cout称号:booknameendl;cout号码:numberendl;返回返回3.1 类与对象的定义在类中直接定义成员函数的情况普通适宜于成员函数规模较小的情况,也就是说它们普通为内联函数,即使没有明确用inline关键字。2在类的定义体中只写出成员函数的原型阐明,而成员函数的定义写在类的定义之后,这种情况比较适宜于成员函数体较大的情况,但这时要求在定义成员函数时,在函数的称号之前加上其所属性类名及作用域运算符“:。定义成员函数的普通类型为:前

10、往值类型类名:成员函数名参数阐明类体返回返回3.1 类与对象的定义此处的:符号叫作用域运算符,用它来指明哪个函数属于哪个类或哪个数据属于哪个类,所以运用类中成员的全名是:类名:成员名。而假设没有类名,那么为全局数据或全局函数非成员函数,也就是说类名是其成员名的一部分。如classRecordprivate:charbookname20;intnumber;public:voidregist(char*a,intb);/成员函数regist的原型voidshow();/成员函数show的原型;/定义图书类Record返回返回3.1 类与对象的定义voidRecord:regist(char*a,

11、intb)/regist()是类Record的/成员函数strcpy(bookname,a);number=b;voidRecord:show()/show()是类Record的成员函数cout称号:booknameendl;cout号码:numberendl;此外,目前开发程序的通常将类的定义写在一个头文件.h文件中,成员函数的定义写在一个程序文件.cpp文件中,这样,就相当于把类的定义头文件看成是类的外部接口,类的成员函数的定义看成类的内返回返回3.1 类与对象的定义部实现。如:对上例可改成将类的定义体写在myapp.h文件中,而成员函数的定义体写在另外一个文件myapp.cpp中:/my

12、app.h文件classRecordprivate:charbookname20;intnumber;public:voidregist(char*a,intb);voidshow();;返回返回3.1 类与对象的定义/myapp.cpp文件#include“iostream.h#include“myapp.h/一定不要忘记嵌入该头文件voidrecord:regist(char*a,intb)strcpy(bookname,a);number=b;voidrecord:show()cout称号:booknameendl;cout号码:number。3.任何对对象私有数据的访问都必需经过向对象

13、发送音讯来实现,而且所发送的音讯还必需是该对象可以识别和接受的。在C+中,音讯发送正是经过公有成员函数的调用来实现的。由于类接口隐藏了对象的内部细节,用户只能经过类接口访问对象,因此,在类设计中必需提供足够的公有接口以捕获对象的全部行为,这正是类设计中的一个最根本的要求。4. 上例中,在对象调用book1.regist(“C+编程教程,1001);时,成员函数regist除了接受两个实参外,还接返回返回3.1 类与对象的定义受了一个对象book1的地址,这个地址被一个隐含的形参this指针所获取,它等同于执行this=&book1,所以一切对数据成员的访问都隐含地被加上前缀:this-,因此,

14、在成员函数体regist中,执行 strcpy(bookname,a);number=b;就等价于strcpy(this-bookname,a); this-number=b;这样,上例中的成员函数regist也可这样定义:void record:regist(char *a,int b) strcpy(this-bookname,a); this-number=b; 经过以上手段就确保了不同对象调用成员函数时访问的是不同对象的数据,而它们之间没有干扰。返回返回3.1 类与对象的定义3.1.5对象赋值语句对象赋值语句对对于于同同一一个个类类生生成成的的两两个个对对象象,可可以以进进展展赋赋值值

15、,其其功功能能是是将将一一个个对对象象的的数数据据成成员员赋赋值值到到另另一一个个对对象象中中去去,赋值语句的左右两边各是一个对象名:赋值语句的左右两边各是一个对象名:【例例3-1】对对于于类类example的的两两个个对对象象obj1和和obj2,让让obj2的的成成员员数数据据的的值值等等于于obj1的的成成员员数数据据的的值值假假定定obj1的成员数据的成员数据num曾经存有数据曾经存有数据215。返回返回3.1 类与对象的定义#include#include/定义类classexampleprivate:/数据成员intnum;public:/函数成员阐明voidset(inti)nu

16、m=i;voiddisp()coutnnum=num;返回返回3.1 类与对象的定义/主程序voidmain()exampleobj1,obj2;obj1.set(215);obj1.disp();obj2=obj1;/对象赋值语句obj2.disp();coutendlendl;3.1.6对象的作用域与生存期对象是类的实例,它本质就是某种数据类型的变量,在不同的位置以不同的方式定义对象时,其作用域和生存期是不同的。返回返回3.1 类与对象的定义如:classDesk/定义Desk类public:intweight;inthigh;intwidth;intlength;classStool/定

17、义Stool类public:intweight;inthigh;intwidth;intlength;返回返回3.1 类与对象的定义deskda;/定义全局对象Stoolsa;voidfn()staticStoolss; /静态部分对象deskda;/定义部分对象/1部分对象不包括部分静态对象其作用域是定义它的函数体,生存期从函数调用开场到函数调用终了,下一次再重新调用函数时,再重新构造对象。构造部分对象的次序即分配存储单元是按它们在函数体中声明的顺序。返回返回3.1 类与对象的定义2静态对象部分静态和全局静态静态对象部分静态和全局静态其其作作用用域域是是定定义义它它的的函函数数体体或或程程序

18、序文文件件,其其生生存存期期是是整整个个程程序序。构构造造静静态态对对象象的的次次序序是是按按它它们们在在程程序序中中出出现现的的次次序序先先后后,并并在在整整个个程程序序运运转转开开场场时时即即在在主主函函数数运运转转前前只构造一次。只构造一次。3全局对象全局对象全全局局对对象象的的作作用用域域是是整整个个程程序序,生生存存期期是是整整个个程程序序的的运运转转时时间间。它它也也是是在在程程序序运运转转前前即即在在主主函函数数运运转转前前只只构造一次。构造一次。4类中成员的构造次序是以类中声明成员的次序进展。类中成员的构造次序是以类中声明成员的次序进展。构造函数和析构函数是类的两种特殊的成员函

19、数。构造函数和析构函数是类的两种特殊的成员函数。返回返回3.2 构造函数与析构函数3.2.1构造函数构造函数构构造造函函数数constructor是是与与类类名名同同名名的的特特殊殊的的成成员员函函数数,当当定定义义该该类类的的对对象象时时,构构造造函函数数将将被被自自动动调调用用以以实实现现对对该该对对象象的的初初始始化化。构构造造函函数数不不能能有有前前往往值值,因因此此不不能能指指定定包包括括void在在内内的的任任何何前前往往值值类类型型。构构造造函函数数的的定定义义体体可可与与其其它它成成员员函函数数成成员员一一样样,放放在在类类内内或或类类外外都都可可。构构造造函数的定义格式为:函

20、数的定义格式为:类名形参阐明类名形参阐明函数体函数体构构造造函函数数既既可可定定义义成成有有参参函函数数,也也可可义义成成无无参参函函数数,要要根根据据问问题题的的需需求求来来定定。全全局局变变量量和和静静态态变变量量在在定定义义时时,将将自自动动赋赋初初值值为为0;部部分分变变量量在在定定义义时时,其其初初始始值值不不固固定定的的。而当对象被定义时,由于对象的意义表达了现实世界的实而当对象被定义时,由于对象的意义表达了现实世界的实返回返回3.2 构造函数与析构函数体,所以一旦定义对象,就必需有一个有意义的初始值,在C+中,在定义对象的同时,给该对象初始化的方法就是利用构造函数。如:【例3-2

21、】类person包括4个数据成员,用来记录人员信息。生成对象obj,并运用构造函数为obj赋予初始值。#include#includeclassPerson/定义类private:/类Person的数据成员charname10;/姓名intage;/年龄intsalary;/薪金char8;/返回返回3.2 构造函数与析构函数public:/构造函数PersonPerson(char*xname,intxage,intxsalary,char*xtel);voiddisp();/函数Person的定义Person:Person(char*xname,intxage,intxsalary,cha

22、r*xtel)strcpy(name,xname);/给各数据成员提供初值age=xage;salary=xsalary;strcpy(,xtel);返回返回3.2 构造函数与析构函数/函数disp的定义voidPerson:disp()coutendl;cout姓名:nameendl;cout年龄:ageendl;cout工资:salaryendl;cout:endlendl;/主函数voidmain()/生成对象obj并初始化Personobj(张立三,25,850,45672314);/显示objobj.disp();返回返回3.2 构造函数与析构函数程序的执行结果是: 姓名:张立三 年

23、龄:25 工资:850 :45672314在 主 函 数 中 的 Person obj (张 立 三 , 25, 850,45672314);中完成了以下几个功能:1. 定义并生成了对象obj。2.在生成对象obj的同时,自动调用相应类的构造函数Person3.将初始值张立三, 25, 850,45672314传送给构造函数Person相应的形参xname, xage,xsalary, xtel。4. 执行构造函数体,将相应的值赋给相应的数据成员。返回返回3.2 构造函数与析构函数3.2.2构造函数的重载构造函数的重载假假设设一一个个类类中中出出现现了了两两个个以以上上的的同同名名的的成成员员

24、函函数数时时,称为类的成员函数的重载。称为类的成员函数的重载。【例例3-3】类类rec定定义义两两个个重重载载函函数数,其其中中一一个个是是无无参参函函数,另一个是有参函数。它们都是构造函数。数,另一个是有参函数。它们都是构造函数。#include#include/定义类定义类classRecprivate:charbookname30;intnumber;返回返回3.2 构造函数与析构函数public:Rec();/第1个构造函数阐明Rec(char*a,intb);/第2个构造函数阐明voidshow();Rec:Rec()/第1个构造函数定义strcpy(bookname,0);numb

25、er=0;Rec:Rec(char*a,intb)/第2个构造函数定义strcpy(bookname,a);number=b;返回返回3.2 构造函数与析构函数voidRec:show()/show的函数定义coutbooknameis:booknameendl;coutbooknumberis:numberendl;voidmain()/主程序Recmybook(“VisualC+6.0,10020);/自动调用构造/函数Rec(char*a,intb)mybook.show();Recyourbook;/自动调用构造函数Rec()yourbook.show();返回返回3.2 构造函数与析

26、构函数程序的执行结果是:booknameis:VisualC+6.0booknumberis:10020booknameis:nonamebooknumberis:0可见,当出现构造函数重载时,其匹配方式同普通函数重载时的匹配方式。返回返回3.2 构造函数与析构函数3.2.3默许构造函数与缺省构造函数默许构造函数与缺省构造函数C+规规定定,每每个个类类必必需需有有一一个个构构造造函函数数。假假设设在在类类中中没没有有显显式式定定义义构构造造函函数数时时,那那么么C+编编译译系系统统在在编编译译时时为为该该类类提提供供一一个个默默许许的的构构造造函函数数,该该默默许许构构造造函函数数是是个个无参

27、函数,它仅担任创建对象,而不做任何初始化任务。无参函数,它仅担任创建对象,而不做任何初始化任务。只只需需一一个个类类定定义义了了一一个个构构造造函函数数不不一一定定是是无无参参构构造造函函数,数,C+编译系统就不再提供默许的构造函数。编译系统就不再提供默许的构造函数。与与变变量量定定义义类类似似,在在用用默默许许构构造造函函数数创创建建对对象象时时,假假设设创创建建的的是是全全局局对对象象或或静静态态对对象象,那那么么对对象象的的默默许许值值为为0,否那么对象的初始值是不定的。,否那么对象的初始值是不定的。当当构构造造函函数数有有缺缺省省参参数数时时,称称为为具具有有缺缺省省参参数数的的构构造

28、函数,在运用时要防止二义性。造函数,在运用时要防止二义性。返回返回3.2 构造函数与析构函数如:classMyclass/定义类Myclassprivate:intmember;public:Myclass();Myclass(inti);Myclass:Myclass()/构造函数Myclassmember=10;返回返回3.2 构造函数与析构函数Myclass:Myclass(inti=10)/构造函数Myclass(inti),该函数/的形参i为缺省参数member=i;voidmain()Myclassx(20);Myclassy; /产生二义性,无法确定自动调用哪个构造/函数完成对象

29、的构造返回返回3.2 构造函数与析构函数3.2.4析构函数析构函数当当一一个个对对象象被被定定义义时时,系系统统自自动动调调用用构构造造函函数数为为该该对对象象分分配配相相应应的的资资源源,当当对对象象运运用用终终了了后后,这这些些系系统统资资源源需求在对象消逝前被释放。需求在对象消逝前被释放。析析构构函函数数是是类类的的一一个个特特殊殊成成员员函函数数,其其函函数数称称号号是是在在类类名名的的前前面面加加上上,它它没没有有前前往往值值,没没有有参参数数,不不能能随随意意调调用用,也也没没有有重重载载,只只是是在在类类对对象象生生命命期期终终了了时时,系系统统自动调用。析构函数的定义方式为:自

30、动调用。析构函数的定义方式为:类名类名函数体函数体注:注:1一个类中只能拥有一个析构函数。一个类中只能拥有一个析构函数。返回返回3.2 构造函数与析构函数2假设程序员在定义类时,没有为类提供析构函数,那么系统会自动创建一个默许的析构函数,其方式为:类名 3对于一个简单的类来说,大多可以直接运用系统提供的默许析构函数。但是,假设在类的对象中分配有动态内存如:用new恳求分配的内容时,就必需为该类提供适当的析构函数,完成清理任务。4对象被析构的顺序与对象建立时的顺序正好相反。即最后构造的对象先被析构。返回返回3.2 构造函数与析构函数【例例3-4】类类Teacher的的构构造造函函数数为为name

31、恳恳求求存存储储空空间间,在析构函数中释放该空间。在析构函数中释放该空间。#include#include/定义类定义类classTeacherprivate:char*name;intage;public:/阐明构造函数阐明构造函数Teacher返回返回3.2 构造函数与析构函数Teacher(char*i,inta)name=newcharstrlen(i)+1;/用new为name成员分配堆内存strcpy(name,i);age=a;coutn执行构造函数Teacherendl;/阐明析构函数TeacherTeacher()deletename;cout执行析构函数Teacherend

32、lendl;voidshow();返回返回3.2 构造函数与析构函数voidTeacher:show()cout姓名:name年龄:ageendl;voidmain()/主程序Teacherobj(张立三,25);obj.show();程序的执行结果是:执行构造函数Teacher姓名:张立三年龄:25执行析构函数Teacher返回返回3.2 构造函数与析构函数3.2.5拷贝构造函数拷贝构造函数拷拷贝贝构构造造函函数数是是C+中中引引入入的的一一种种新新的的构构造造函函数数。定定义一个拷贝构造函数的方式是:义一个拷贝构造函数的方式是:类名类名const类名类名&方式参数方式参数函数体函数体由此可

33、看出:由此可看出:1拷拷贝贝构构造造函函数数的的称称号号与与类类的的称称号号一一样样,且且它它只只需需一一个参数,该参数就是对该类对象的援用。个参数,该参数就是对该类对象的援用。2拷拷贝贝构构造造函函数数的的功功能能是是用用于于实实现现对对象象值值的的拷拷贝贝,经经过过将将一一个个同同类类对对象象的的值值拷拷贝贝给给一一个个新新对对象象,来来完完成成对对新新对象的初始化,即用一个对象去构造另外一个对象。对象的初始化,即用一个对象去构造另外一个对象。返回返回3.2 构造函数与析构函数【例例3-5】Example是是一一个个人人员员信信息息类类。用用普普通通构构造造函函数数生成生成obj1,用拷贝

34、构造函数生成,用拷贝构造函数生成obj2。#include#includeclassExampleprivate:char*name;intnum;public:example(inti,char*str)/构造函数定义构造函数定义name=str;num=i;返回返回3.2 构造函数与析构函数example(constExample&x)/拷贝构造函数定义num=x.num;voidlist()/定义显示函数listcout数据成员num的值=numendlendl;voidmain()exampleobj1(215,“张立三);/调用函数Example(inti,char*str)构造ob

35、j1exampleobj2(obj1);/运用拷贝构造函数构造obj2obj2.list();/显示obj2的值/其它程序部分返回返回3.2 构造函数与析构函数程序的执行结果是:数据成员num的值=215数据成员num的值=215阐明:1上例中在main函数中的语句Example obj2(obj1);在执行时,系统会自动调用类Example的拷贝构造函数完成对obj2对象的构造。2假设程序员没有为所设计的类提供显式的拷贝构造函数,那么系统会自动提供一个默许的拷贝构造函数,其功能是:把作为参数的对象的数据成员逐个拷贝到目的变量中,这称为成员级复制或浅拷贝。返回返回3.2 构造函数与析构函数3.

36、2.6一个一个类的的对象作象作为另一个另一个类的数据成的数据成员一一个个类中中的的数数据据成成员除除了了可可以以是是int,char,float等等这些些根根本本的的数数据据类型型外外,还可可以以是是某某一一个个类的的一一个个对象象。用用子子对象象创建新建新类。在在C+中中,当当把把一一个个类的的对象象作作为新新类的的数数据据员时,那么新那么新类的定的定义格式可表示格式可表示为:classX类名名1成成员名名1;类名名2成成员名名2;类名名n成成员名名n;/其它成其它成员;返回返回3.2 构造函数与析构函数3假设一个类A的对象作为另一个类B的数据成员,那么在类B的对象创建过程中,调用其构造函数

37、的过程中,数据成员类A的对象会自动调用类A的构造函数。但应留意:假设类A的构造函数为有参函数时,那么在程序中必需在类B的构造函数的括号后面加一“:和被调用的类A的构造函数,且调用类A的构造函数时的实参值必需来自类B的形参表中的形参。这种方法称为初始化表的方式调用构造函数。如:以上面定义的类X为例,在对类X的对象进展初始化时,必需首先初始化其中的子对象,即必需首先调用这些子对象的构造函数。因此,类X的构造函数的定义格式应为:X:X参数表0:成员1参数表1,成员2参数表2,成员n(参数表n) 返回返回3.2 构造函数与析构函数其中,参数表1提供初始化成员1所需的参数,参数表2提供初始化成员2所需的

38、参数,依此类推。并且这几个参数表的中的参数均来自参数表0,另外,初始化X的非对象成员所需的参数,也由参数表0提供。在构造新类的对象过程中,系统首先调用其子对象的构造函数,初始化子对象;然后才执行类X本人的构造函数,初始化类中的非对象成员。对于同一类中的不同子对象,系统按照它们在类中的阐明顺序调用相应的构造函数进展初始化,而不是按照初始化表的顺序。返回返回3.2 构造函数与析构函数【例例3-6】以以下下定定义义了了三三个个Student、Teacher和和Tourpair,其其中中Student类类的的对对象象和和Teacher类类的的对对象象作作为为了了Tourpair的的数数据据成成员员,察

39、察看看对对象象的的构构造造过过程程和和构构造造函函数数被执行的顺序。被执行的顺序。#includeclassStudentpublic:Student()coutconstructstudent.n;semeshours=100;gpa=3.5;返回返回3.2 构造函数与析构函数protected:intsemeshours;floatgpa;classTeacherpublic:Teacher()coutconstructTeacher.n;返回返回3.2 构造函数与析构函数classTourpairpublic:Tourpair()coutconstructtourpair.n;nomee

40、ting=0;protected:Studentstudent;Teacherteacher;intnomeeting;返回返回3.2 构造函数与析构函数voidmain()Tourpairtp;coutbackinmain.n;其执行结果是:constructstudent.constructteacher.constructtourpair.backinmain.由此可见:主函数main()运转开场时,遇到要创建Tourpair类的对象,于是调用其构造函数Tourpair,该构造启动时,首先分配对象空间包含一个Student对返回返回3.2 构造函数与析构函数象、一个Teacher对象和一

41、个int型数据,然后根据其在类中声明的对象成员的次序依次调用其构造函数。即先调用Student()构造函数,后调用Teacher()构造函数,最后才执行它本人的构造函数的函数体。由于上例中Tourpair类的数据成员student和teacher的构造函数都是无参函数,所以系统在构造student和teacher对象时会自动调用各自的构造函数Student()和Teacher(),而不需求用初始化表的方式去调用。【例3-7】试分析以下程序的执行结果:#include#include返回返回3.2 构造函数与析构函数classStudentpublic:Student(char*pName=No

42、name)cout构造新同窗:pNameendl;strncpy(name,pName,sizeof(name);namesizeof(name)-1=0;Student(Student&s)cout构造copyofs.nameendl;strcpy(name,copyof);strcat(name,s.name);返回返回3.2 构造函数与析构函数Student()cout析构nameendl;protected:charname40;classTutorpublic:Tutor(Student&s):student(s)/此为初始化表,调用/Student的拷贝构造函数cout构造指点教师

43、n;protected:Studentstudent;返回返回3.2 构造函数与析构函数voidmain()Studentst1;/此处调用Student的构造函数Student(char*pName=Noname)Studentst2(zhang);/同上Tutortutor(st2);/此处调用Tutor的构造函数Tutor(Student&s)/在构造tutor对象的过程中,用初始化表调用/Student类的拷贝构造函数Student(Student&s)执行结果如下:构造新同窗:Noname构造新同窗:zhang构造copyofzhang返回返回3.2 构造函数与析构函数构造指点教师析

44、构copyofzhang析构zhang析构Noname3.2.7利用初始化表对常量数据成员或援用成员提供初值如前所述,构造函数可对对象的数据成员进展初始化,但假设数据成员为常量成员或援用成员时,就有所不同,如:classSillyclasspublic:Sillyclass()/此构造函数对成员ten和refi的初始化错误。ten=10;refi=i;返回返回3.2 构造函数与析构函数protected:constintten;/常量数据成员tenint&refi;/援用refi;阐明:1.呵斥以上错误的缘由是在Sillyclass类的构造函数进入之后开场执行其函数体时,对象构造曾经建立,数据

45、成员ten和refi已存在,而其数据成员ten为const,而refi为援用,所以在构造函数体内不能再对其指派新的值。2.处理以上问题的方法是利用初始化表:在构造函数的括号后面加一“:和初始化表,初始化表的格式是:数据成员名值,假设有多个时,需求用逗号隔开。返回返回3.2 构造函数与析构函数【例例3-8】类类employee中中包包括括私私有有数数据据成成员员x,和和2个个公公有有函函数成员数成员example、show。程序中运用初始化表是。程序中运用初始化表是x(215)。#include#include/定义类定义类employeeclassemployeeprivate:constin

46、tx;public:employee();voidshow();返回返回3.2 构造函数与析构函数/employee的类外定义employee:employee():x(215)/初始化表/show()的定义。voidemployee:show()coutnx的值是:xendl;/主函数voidmain()/生成对象并为x赋予初始值employeeobj;/调用show显示x的值obj.show();返回返回3.2 构造函数与析构函数3.2.8 3.2.8 类作用域类作用域 类类作作用用域域又又可可称称为为类类域域,它它是是指指在在类类定定义义中中用用一一对对大大括括号号所所括括起起来来的的范

47、范围围。由由于于在在程程序序文文件件中中可可包包含含类类,而而类类中中又又包包含含函函数数,因因此此,类类域域显显然然是是一一个个小小于于文文件件域域,而大于函数域的概念。而大于函数域的概念。 由由于于在在一一个个类类中中既既可可定定义义变变量量数数据据成成员员,又又可可定定义义函函数数成成员员函函数数,所所以以,类类域域在在许许多多方方面面与与文文件件域域类类似似。但但是是,在在类类域域中中定定义义的的变变量量不不能能运运用用autoauto、registerregister和和externextern等等修修饰饰符符,而而且且在在类类域域中中定定义义的的函函数数也也不不能能运运用用exte

48、rnextern修修饰饰符符。同同时时,在在类类域域中中定定义义的的静静态态成员和成员函数还具有外部的衔接属性。成员和成员函数还具有外部的衔接属性。返回返回3.2 构造函数与析构函数【例【例3-93-9】类域及其成员援用举例】类域及其成员援用举例, ,设以下程序代码被存设以下程序代码被存放到了一个程序文件中。放到了一个程序文件中。 #include #include class Myclassclass Myclass private: private: int x; int x; int y; int y; public: public: Myclass(int a,int b) x=a;y

49、=b; Myclass(int a,int b) x=a;y=b; void print(); void print(); void myfunc(); void myfunc();返回返回3.2 构造函数与析构函数voidMyclass:print()coutx=x,y=yendl;voidMyclass:myfunc()intx=9,y=10;coutInmyfunc:x=x,y=yendl;/输出部分变量/输出类的数据成员coutMyclass:x=Myclass:x,Myclass:y=Myclass:ymyfunc();程序的运转结果为:x=100,y=200Inmyfunc:x=9

50、,y=10Myclass:x=100,Myclass:y=200阐明:1类成员函数的原型在类的定义体中声明,具有类作用域,但其实现部分在类的定义体外。由于不同类的成员函数可以具有一样的名字,因此,需求用作用域运算符“:来指明该成员函数所属的类。返回返回3.2 构造函数与析构函数2类中的成员拥有类作用域,因此在成员函数中可以直接援用类的数据成员。但是,假设在成员函数中定义了同名的部分变量时,那么必需用作用域运算符“:来指定,以免混乱。如:上例中的myfunc()函数中定义了与类的数据成员同名的部分变量x、y,所以在myfunc()函数中要访问类中的数据成员x和y的值时,必需加上作用域运算符。3类

51、中的成员拥有类的作用域,假设要从类外访问类的成员时,那么必需经过对象名或指向对象的指针。当经过对象名时,应运用圆点成员选择符“.;当经过指针时,应运用箭头成员选择符“-。如上例中的test.print();与ptest-myfunc();返回返回3.3 承继和派生3.3.1承承继的概念的概念一一个个类的的数数据据成成员和和成成员函函数数,有有些些是是类本本身身本本人人定定义的,有一些是可承的,有一些是可承继的或的或经过模板生成的。模板生成的。所所谓承承继inheritance就就是是利利用用已已有有的的数数据据类型型定定义出出新新的的数数据据类型型。利利用用类的的“承承继,就就可可以以将将原原

52、来来的的程程序序代代码反反复复运运用用,从从而而减减少少了了程程序序代代码的的冗冗余余度度,符符合合软件件重重用用的的目目的的。所所以以说,承承继是是面面向向对象象程程序序设计的的一一个个重重要要机机制制。另另外外,在在C+中中扩展展派派生生类成成员的的方方法法是是非非常常灵灵敏敏的的。派派生生类不不仅可可以以承承继原原来来类的的成成员,还可以可以经过以下方式以下方式产生新的成生新的成员:返回返回3.3 承继和派生1添加新的数据成员;2添加新的成员函数;3重新定义已有成员函数;4改动现有成员的属性。在承继关系中,称被承继的类为基类baseclass或父类,而把经过承继关系定义出来的新类称为派生

53、类derivedclass子类。由此可见,派生类既可以对基类的性质进展扩展,又可以进展限制,从而得到更加灵敏、更加适用的可重用模块,大大缩短程序的开发时间。返回返回3.3 承继和派生3.3.2单承继单承继1.定义派生类定义派生类在基类的根底上定义其派生类的定义方式为:在基类的根底上定义其派生类的定义方式为:class派生类名:访问方式派生类名:访问方式基类名基类名派生类中的新成员派生类中的新成员其中:其中:1派生类名由用户本人命名;派生类名由用户本人命名;2访访问问方方式式即即承承继继方方式式,可可以以为为public或或private,默默以以为为private方方式式。访访问问方方式式为为

54、public方方式式时时,这这种种承承继继称称为为公公有有承承继继,而而访访问问方方式式为为private方方式式时时,称称为为私私有有承承继;继;3基类名必需是程序中一个已有的类。基类名必需是程序中一个已有的类。返回返回3.3 承继和派生4在冒号“:后的部分通知系统,这个派生类是从哪个基类派生的,以及在派生时的承继方式。5大括号内的部分是派生类中新定义的成员。2基类与派生类之间的关系1派生类不仅拥有属于本人的数据成员与成员函数,还坚持了从基类承继来的数据成员与成员函数;同时派生类可对一些承继来的函数重新定义,以顺应新的要求。2C+关于类的承继方式的规定,如下表3.1所示:按private方式

55、承继即私有承继时,基类中的公有成员和维护成员在派生类中皆变为私有成员。 按public方式承继即公有承继时,基类中的公有成员和维护成员在派生类中不变。返回返回3.3 承继和派生无论哪种承继方式,基类的私有成员均不能承继。这与私有成员的定义是一致的,符合数据封装的思想。在公有承继方式下,基类的公有成员和维护成员被承继为派生类成员时,基访问属性不变。留意:私有成员与不可访问成员是两个不同的概念。某个类的私有成员只能被该类的成员函数所访问,而类的不可访问成员甚至不能被该类本身的成员函数所访问。类的不可访问成员总是从某个基类派生来的,它要么是基类的私有成员,要么是基类的不可访问成员。基类公有派生类私有

56、派生类public成员public成员private成员protected成员protected成员private成员private成员无法承继无法承继返回返回3.3 承继和派生3在C+中,可以根据需求定义多层的承继关系,也可以从一个基类派生出多个类,构成类的层次构造,在类的层次构造中,处于高层的类,表示最普通的特征,而处于底层的类,表示更详细的特征,在多层承继关系中,基类与派生类的关系是相对的,例如:由类A派生出类B,再由类B派生出类C,这里类B相对于类A是派生类,而相对于类C是基类,并称类C是类A的间接派生类,称类A是类C的间接基类;而称具有直接派生关系的两个类分别为直接派生类和直接基类。

57、【例3-9】类Build_1是一个关于楼房数据的类。它的数据成员有posi_x、posi_y和area,分别是楼房位置的经、纬度和建筑面积。它的函数成员只需set1,用于设置数据成员posi_x、posi_y和area的值。让Build_1作为基类,再添加数据成员high、函数成员set2和disp来定义派生类Build_2。返回返回3.3 承继和派生#includeclassBuild_1 /定义基类protected:intposi_x; /有三个维护型的数据成员intposi_y;intarea;public:voidset1(intx,inty,inta)posi_x=x;posi_y

58、=y;area=a;/定义派生类Build_2classBuild_2:publicBuild_1返回返回3.3 承继和派生intheight;public:voidset2(inth)height=h;voiddisp()coutn经度:posi_xendl;cout纬度:posi_yendl;cout高度:heightendl;cout面积:areaendlendl;voidmain()/用Build_2生成对象obj返回返回3.3 承继和派生Build_2obj;obj.set1(100,200,300);obj.set2(400);obj.disp();程序执行的结果是:经度:100纬

59、度:200高度:400面积:300由此可见:派生类Build_2中已承继了基类Build_1中的数据成员posi_x、posi_y、area和基类中的成员函数set1,并同时添加了新的成员height和成员函数set2、disp。返回返回3.3 承继和派生3派生派生类的数据成的数据成员和成和成员函数、构造函数、构造过程与构造函数程与构造函数1派派生生类的的数数据据成成员和和成成员函函数数的的来来源源有有两两个个,一一个个来来源源是是从从基基类承承继来来的的数数据据成成员和和成成员函函数数,对于于承承继来来的的数数据据成成员,即即使使没没有有用用也也不不能能取取消消,只只能能不不理理睬睬它它们,

60、但但允允许对一一些些承承继来来的的成成员函函数数重重新新定定义,即即在在原原有有基基类的的成成员函函数数的的根根底底上上,再再添添加加一一些些操操作作,以以完完成成派派生生类所所要要求求的的操操作作。另另一一个个来来源源就就是是由由派派生生类本本人人定定义的的数数据据成成员和和成成员函函数数,这些些成成员的的定定义方方法法同同普普通通类成成员的定的定义方法根本一方法根本一样。2经过派派生生类的的对象象调用用一一个个被被重重新新定定义过的的基基类的的成成员函函数数,所所调用用的的是是派派生生类的的成成员函函数数,此此时,假假想想象象调用用基基类的的成成员函函数数,必必需需在在成成员函函数数名名前

61、前加加基基类名名作用域分隔符作用域分隔符“:。:。返回返回3.3 承继和派生3在创建派生类的对象时,由于派生类的对象包含了基类的数据成员,因此派生类的构造函数除初始化其本身定义的数据成员外,还必需对基类中的数据成员进展初始化,也就是说,派生类的构造函数要担任调用基类的构造函数。所以派生类的构造函数的定义格式如下:派生类名:派生类构造函数名参数表:基类构造函数名参数表4虽然派生类可以直接访问基类的维护数据成员,甚至在构造时初始化它们,但是普通不这么做,而是经过基类的接口成员函数去访问它们,初始化也是经过基类的构造函数。这样,防止了类与类之间的相互关扰。返回返回3.3 承继和派生5基类的对象只能调

62、用基类的成员函数,不能调用派生类的成员函数。6在定义派生类的对象时,系统首先执行基类的构造函数,然后执行派生类的构造函数。而系统执行析构函数的顺序恰恰相反,即先执行派生类的析构函数,再执行基类的析构函数。7假设在基类中没有定义任何构造函数,这时在派生类的构造函数的定义中可以省略对基类构造函数的调用,此时系统将去调用基类的默许构造函数。如: 【例3-10】本例中分别定义一个描画圆的类Ccircle和描画一个圆柱体的类Ccylinder。返回返回3.3 承继和派生#includeiostream.hclassCcircle/定义圆类protected:doubleradius;public:Cci

63、rcle(doubleradiusval)radius=radiusval;voidsetradius(doubleradiusval)radius=radiusval;doublegetradius()constreturnradius;返回返回3.3 承继和派生doublearea()constreturn3.14*radius*radius;classCcylinder:publicCcircle/定义圆柱体类protected:doubleheight;public:Ccylinder(doubleradiusval,doubleheightval);voidsetheight(dou

64、bleheightval)height=heightval;doublegetheight()constreturnheight;返回返回3.3 承继和派生doublearea()const/重新定义area()函数/此处调用的是基类的成员函数area(),必需加:return2*Ccircle:area()+2*3.14*radius*height;Ccylinder:Ccylinder(doubleradiusval,doubleheightval):Ccircle(radiusval)/调用Ccircle类的构造函数对radius初始化/派生类Ccylinder的构造函数不但初始化本身定

65、义的成员height,而且经过调用基类的构造函数Ccircle初始化从基类承继来的数据成员radiusheight=heightval;返回返回3.3 承继和派生voidmain()Ccirclecircle(10);Ccylindercylinder(2,5);cout圆柱体外表积:cylinder.area()endl;cout圆柱体底面积:cylinder.Ccircle:area()endl;cout圆的面积是:circle.area();程序的执行结果为:圆柱体外表积:87.92圆柱体底面积:12.56圆的面积是:314返回返回3.3 承继和派生程序阐明:1求圆的面积与圆柱体的外表积

66、的方法是不同的。因此,在派生类Ccylinder中重新定义了基类成员函数area()。在主函数中,经过基类和派生类的不同对象,分别调用了这两个area()函数。2由于承继关系,在类Ccylinder中存在两个同名的函数arear()。其中一个是从基类Ccircle中承继过来的,另一个是在派生类Ccylinder中新定义的。这样,当经过派生类对象调用area()函数时,C+编译器将沿承继关系搜索,运用离调用对象最近的那个版本的函数。3假设确实想经过Ccylinder的对象访问从基类Ccircle承继过来的area()函数,那么必需运用作用域运算符“:显式指明。返回返回3.3 承继和派生经过以上分

67、析可知,C+中处置同名函数有以下3种根本方法: 1根据函数的参数的特征进展区分。即编译器根据函数的类型或个数进展区分。如:max(int,int)max(float,float)2根据类对象进展区分。如:在上例中的main函数中,cylinder.area()circle.area()其中,cyclinder是Ccylinder的一个对象,circle是Ccircle的一个对象。3运用作用域运算符“:进展区分,如:Ccircle:area()以上三种区分方法都是在程序编译过程中完成的,称为静态联编,除此之外,C+还提供称为动态联编。 返回返回3.3 承继和派生3.3.3多重承多重承继在在单一一

68、承承继关关系系中中,每每个个派派生生类最最多多只只需需一一个个直直接接基基类,但但它它可可以以有有多多个个间接接基基类。在在C+中中不不仅支支持持单一一承承继,而而且且也也支支持持多多重重承承继,所所谓多多重重承承继,是是指指派派生生类从从多多个个基基类中中派派生生而而来来,使使派派生生类承承继多多个个基基类的的特特征征,在在多多重重承承继关关系系中中,派派生生类有有多多个个直直接接基基类。定定义多多重重承承继类的方式如下:的方式如下:class派生派生类名:名:访问方式方式基基类名,名,访问方式方式基基类名名;其中:其中:访问方式方式为public或或private,功能同,功能同单一承一承

69、继。多重承多重承继下派生下派生类的构造函数必需同的构造函数必需同时担任一切基担任一切基类构构返回返回3.3 承继和派生造函数的调用,对于派生类构造函数的参数个数必需同时满足多个基类初始化的需求。所以,在多重承继下,派生类的构造函数的定义格式如下:派生类构造函数名参数表:基类名1(参数表1),在多重承继下,系统首先执行各基类的构造函数,然后再执行派生类的构造函数,处于同一层次的各基类构造函数的执行顺序与声明派生类时所指定的各基类顺序一致,而与派生类的构造函数定义中所调用基类构造函数的顺序无关。返回返回3.3 承继和派生【例例3-11】测试多多重重承承继关关系系下下,基基类和和派派生生类的的构构造

70、造函函数的数的执行行顺序。序。#include“iostream.hclassB1protected:intb1;public:B1(intval1)b1=val1;coutbase1iscalled“endl;返回返回3.3 承继和派生classB2protected:intb2;public:B2(intval2)b2=val2;coutbase2iscalledendl;classD:publicB1,publicB2protected:intd;返回返回3.3 承继和派生public:D(intval1,intval2,intval3);D:D(intval1,intval2,intv

71、al3):B1(val1),B2(val2)/如 改 为 D:D(int val1, int val2, int val3): B2(val2),B1(val1)效果一样d=val3;couterivedclassiscalled“;voidmain()Ddobj(1,2,3);返回返回3.3 承继和派生该程序的执行结果是:基类B1的构造函数被调用基类B2的构造函数被调用派生类D的构造函数被调用3.3.4虚基类多重承继下,一个派生类可从多个基类派生出来,又由于一个基类可派生出多个派生类,因此能够会产生一个类是经过多条途径从一个给定的类中派生出来的,如图3.1所示。BBD1D2D3图3.1多重承

72、继的二义性返回返回3.3 承继和派生从上图可以看出:派生类D3中将承继两份类B的成员,一份由类D1派生得到,另一份由D2派生而来,这时经过派生类D3的对象访问类D1和D2的成员不会有问题,但访问类B的成员就会出现模棱两可的景象,编译程序不知道究竟要访问哪一份的成员,C+为此提供了虚基类,以处理这种二义性。虚基类是这样的一个基类:它虽然被一个派生类间接地多次承继,但派生类却只承继一份该基类的成员,这样,防止了在派生类中访问这些成员时产生二义性。将一个基类声明为虚基类必需在各派生类定义时,在基类的称号前面加上关键字virtual,格式如下:class派生类名:virtualpublic基类名/声明

73、派生类成员;返回返回3.3 承继和派生运用虚基类时,要特别留意派生类的构造函数,对于普通基类,派生类的构造函数担任调用其直接基类的构造函数以初始化其直接基类的数据成员,而对于虚基类的任何派生类,其构造函数不仅担任调用直接基类的构造函数,还需调用虚基类的构造函数,如图3.1所示的构造中,假设基类B被声明为虚基类,那么派生类D3担任调用三个基类直接基类D1、D2和虚基类B的构造函数,而派生类D1和D2不会调用虚基类B的构造函数,只由最终端的派生类D3担任调用虚基类的构造函数。如:classB/定义类Bprotected:intb;public:B(intbval=0)返回返回3.3 承继和派生b=

74、bval;classD1:virtualpublicBprotected:intd1;public:D1(intbval,intdval);D1:D1(intbval,intdval):B(bval)d1=dval;classD2:virtualpublicBprotected:intd2;返回返回3.3 承继和派生public:D2(intbval,intdval);D2:D2(intbval,intdval):B(bval)d2=dval;classD3:publicD1,publicD2protected:intd3;public:D3(intbval,intdval1,intdval2

75、,intdval3);D3:D3(int bval, int dval1,int dval2,int dval3):D1(bval,dval1),D2(bval,dval2),B(bval)d3=dval3;返回返回3.4 虚函数与多态性3.4.1多态性多态性多多态态性性就就是是指指同同样样的的音音讯讯被被类类的的不不同同的的对对象象接接纳纳时时导导致致的的完完全全不不同同的的行行为为的的一一种种景景象象。这这里里所所说说的的音音讯讯即即对对类成员函数的调用。类成员函数的调用。C+支支持持两两种种不不同同类类型型的的多多态态:一一种种是是编编译译时时的的多多态态,另另一一种种是是运运转转时时的

76、的多多态态。在在编编译译时时的的多多态态是是经经过过静静态态联联编编实实现现的的;而而在在运运转转时时的的多多态态那那么么是是经经过过动动态态联联编编实实现现的。的。很很明明显显,函函数数的的重重载载实实现现了了一一种种多多态态性性;这这里里要要讲讲的的多多态态性性是是建建立立在在虚虚函函数数的的概概念念和和方方法法根根底底之之上上,经经过过虚虚函函数数来来实实现现的的,而而虚虚函函数数又又必必需需存存在在于于承承继继的的环环境境下下。利利用用多多态态性性,用用户户可可以以发发送送普普通通方方式式的的音音讯讯,而而将将一一切切的的实实现现细细节节留留给给了了音音讯讯的的对对象象,所所以以说说多

77、多态态性性与与数数据据封封装和承继共同构成面向对象程序设计的三大机制。装和承继共同构成面向对象程序设计的三大机制。返回返回3.4 虚函数与多态性3.4.2 3.4.2 子类型子类型 C+C+中中的的动动态态联联编编是是经经过过虚虚函函数数实实现现的的,而而要要了了解解虚虚函函数数必需首先讨论一个与之相关的概念,即子类型。必需首先讨论一个与之相关的概念,即子类型。 假假设设一一个个特特定定的的类类型型S S,当当且且仅仅当当它它提提供供了了类类型型T T的的行行为为时时,那那么么称称类类型型S S是是类类型型T T的的子子类类型型。子子类类型型表表达达了了类类型型间间的普通与特殊的关系。的普通与

78、特殊的关系。在在C+C+中中,子子类类型型的的概概念念是是经经过过公公有有承承继继或或公公有有派派生生来实现的。来实现的。根根据据承承继继方方式式的的概概念念,我我们们知知道道,按按公公有有承承继继的的方方式式产产生生的的派派生生类类中中,必必然然包包含含了了原原来来基基类类中中的的全全部部成成员员。因因此此,一一个个公公有有派派生生类类的的对对象象可可以以提提供供其其基基类类对对象象的的全全部部行行为为基基类类的的全全部部接接口口,也也就就是是说说,在在程程序序中中可可以以把把一一个个公公有有派生类对象当作其基类对象来处置。派生类对象当作其基类对象来处置。返回返回3.4 虚函数与多态性【例【

79、例3-133-13】子类型的概念及实现例如。】子类型的概念及实现例如。#include #include class A /class A /定义类定义类A Aprivate:private: int a; int a; public: public: A(int i=0)a=i; A(int i=0)a=i; void print(); void print(); ; ;void A:print ()void A:print () coutIn coutIn class class A, A, print() print() is is called.endl; called.endl; 返

80、回返回3.4 虚函数与多态性classB:publicA/定义类B,类B是类A的公有派生类private:intb;public:B(intj=-1)b=j;voidcommfun(A&aref)aref.print();返回返回3.4 虚函数与多态性voidmain()Aa;commfun(a);/以基类A的对象a作为实参调用函数commfunBb;commfun(b);/以派生类B的对象b调用函数commfun程序的运转结果为:InclassA,print()iscalled.InclassA,print()iscalled.阐明:返回返回3.4 虚函数与多态性1在本例中,类B是类A的公有

81、派生类,函数commfun()的形参是一个基类A对象的援用,所以在main函数中,把基类A的对象a作为实参调用函数commfun()时,产生的结果是不言而喻的。但在main函数中,当把类B的对象b作为实参调用函数commfun()时,函数commfun()仍能正常任务,且打印结果与对象a作为实参时的结果一样,这阐明,在程序中可以把一个公有派生类对象当作其基类对象来处置。2将类型B的对象b传送给函数commfun()处置是在程序运转时发生的。但在程序编译时,编译器只能对源程序代码进展静态检查。3子类型的重要性在于可以减轻程序员编写程序代码的负担。返回返回3.4 虚函数与多态性3.4.3用基类指针

82、指向公有派生类对象用基类指针指向公有派生类对象既既然然一一个个公公有有派派生生类类对对象象可可以以当当作作基基类类对对象象运运用用,那那么么,指指向向基基类类的的指指针针自自然然也也可可以以指指向向其其公公有有派派生生类类对对象象。因因此此,基基类类指指针针、派派生生类类指指针针、基基类类对对象象和和派派生生类类对对象象四四者间有以下四种组合的情况:者间有以下四种组合的情况:1直接用基类指针指向基类对象。直接用基类指针指向基类对象。2直接用派生类指针指向派生类对象。直接用派生类指针指向派生类对象。3用基类指针援用其派生类对象。用基类指针援用其派生类对象。4用派生类指针援用基类对象。用派生类指针

83、援用基类对象。由由于于1、2两两种种情情况况,指指针针类类型型和和对对象象类类型型一一致致,因此完全行得通。因此完全行得通。返回返回3.4 虚函数与多态性对于第3种情况,由于可以把一个公有派生类对象当作基类对象处置,所以可以用基类指针指向其派生类对象。但必需留意的是,由于基类指针本身的类型并没有改动,因此基类指针仅能访问派生类中的基类部分。在程序中,当把派生类对象的指针赋给基类指针时,编译器能自动完成隐式类型转换。对于第4种情况,将派生类指针直接指向基类对象是危险的,由于编译器不允许这么做,也不提供隐式类型转换。当然,程序员假设采用强迫类型转换,也可以把基类指针转换为派生类指针,但这时要正确地

84、运用该指针。返回返回3.4 虚函数与多态性【例例3-14】基基类类指指针针、派派生生类类指指针针、基基类类对对象象和和派派生生类类对象四者间组合的运用情况例如。对象四者间组合的运用情况例如。#includeclassA/定义类定义类Aprivate:inta;public:A(inti=1)a=i;voidprint();intgeta();voidA:print()couta=aendl;返回返回3.4 虚函数与多态性intA:geta()returna;classB:publicA/定义类B,类B是类A的公有派生类private:intb;public:B(intj=-1)b=j;void

85、print();voidB:print()coutb=bprint();pb=&bb;/派生指针可以指向派生类对象pb-print();pa=&bb;/基类指针可以指向派生类对象coutgeta()getb();那么错误,/由于基类指针仅能看到派生类中的基类部分pa-print();bb.print();返回返回3.4 虚函数与多态性pb=(B*)pa;/经过强迫类型转换,派生类指针也可以/指向基类对象/上面语句如改为pb=pa;那么错误,由于派生类指针不可/以直接指向基类对象程序的运转结果:a=10b=201a=1b=20返回返回3.4 虚函数与多态性程序分析:在上例的main函数中,虽然基

86、类指针pa指向派生对象bb即:pa=&bb,但语句pa-print()与语句bb.print()的输出结果并不一样,从结果来看,前者的输出结果是“a=1,而后者的输出结果为“b=20。这是由于虽然一个基类指针可以指向其派生类对象,但指针本身的属性并没有改动,因此,系统以为它所指向的依然是一个基类对象,于是就只能调用其基类的成员函数print()。进一步分析发现,在派生类B中虽然承继了基类A的成员函数print(),但为了顺应派生类本人的需求,在派生类中曾经改动了这个函数的实现,即在派生类中又定义了一个同名的print()函数,而这种改动在静态联编的条件上编译器并不知道,以致于呵斥以上结果的不一

87、致。所以,必需通知编译器这种能够的改动,即需求进展动态联编。其方法就是在基类中将能够发生改动的成员函数声明为虚函数。返回返回3.4 虚函数与多态性3.4.虚函数虚函数C+经过虚虚函函数数实现了了多多态性性,而而虚虚函函数数存存在在于于承承继环境境中中,在在承承继关关系系下下,派派生生类作作为基基类的的子子类,在在任任何要求基何要求基类对象的地方运用派生象的地方运用派生类对象是有意象是有意义的。的。声声明明虚虚函函数数的的方方法法是是在在基基类中中的的成成员函函数数原原型型前前加加上上关关键字字virtual。其格式如下:。其格式如下:class类名名virtual类型型函数名参数表;函数名参数

88、表;;当当一一个个类的的成成员函函数数阐明明为虚虚函函数数后后,就就可可以以在在该类的的直接或直接或间接派生接派生类中定中定义与其基与其基类虚函数原型相虚函数原型相返回返回3.4 虚函数与多态性同的函数。这时,当用基类指针指向这些派生类对象时,系统会自动用派生类中的同名函数来替代基类中的虚函数。也就是说,当用基类指针指向不同派生类对象时,系统会在程序运转中根据所指向对象的不同,自动选择适当的函数,从而实现了运转时的多态性。虚函数可以在一个或多个派生类中被重新定义,因此,属于函数重载的情况,但这种重载与普通的函数重载是不同的,要求在派生类中重新定义时,必需与基类中的函数原型完全一样,包括函数名、

89、前往类型、参数个数和参数类型的顺序。这时无论在派生类的相应成员函数前能否加上关键字virtual,都将视其为虚函数,假设函数原型不同,只是函数名一样,C+将视其为普通的函数重载,而不是虚函数。只需类的成员函数才干声明为虚函数,全局函数及静态成员函数不能声明为虚函数。返回返回3.4 虚函数与多态性【例【例3-153-15】虚函数的定】虚函数的定义与运用与运用举例。例。#include “iostream.h#include “iostream.hclass Baseclass Base public: public: virtual virtual void void show() show()

90、 coutcoutbase base classnclassn; ; ;class Der1: public Baseclass Der1: public Base public: public: void void show() show() coutcoutderived derived class class 1 1 nn; ; ; ;class Der2: public Baseclass Der2: public Base public: public: void show() cout void show() coutshow();p=&dobj1;p-show();p=&dobj

91、2;p-show();返回返回3.4 虚函数与多态性程序的运转结果:baseclassderivedclass1derivedclass2由上例可以看出:1经过虚函数实现了运转时的多态性。2基类用虚函数提供了一个派生类对象都具有的共同界面,派生类又各自对虚函数定义本人的详细实现,这样,使得程序既简约又具有扩展性,并能协助程序员控制更大的复杂性。假设派生类中没有重新定义基类的虚函数,那么该派生类直接承继其基类的虚函数。3当一个函数在基类被声明为虚函数后,不论阅历多少层派生,都将坚持其虚拟性。返回返回3.4 虚函数与多态性3.4.5 3.4.5 静态联编与动态联编静态联编与动态联编在在向向对对象象

92、的的程程序序设设计计中中,联联编编的的含含义义是是指指把把一一个个音音讯讯和和一一个个方方法法联联络络在在一一同同,也也就就是是把把一一个个函函数数名名与与其其实实现现代代码码联联络络在在一一同同。根根据据实实现现联联编编的的阶阶段段的的不不同同,可可分分为为静静态态联联编编和动态联编两种。和动态联编两种。静静态态联联编编是是在在编编译译阶阶段段进进展展的的。而而动动态态联联编编是是在在程程序序运运转转过程中,根据程序运转的需求进展的联编。过程中,根据程序运转的需求进展的联编。实实现现静静态态联联编编的的前前提提是是:在在编编译译阶阶段段就就必必需需可可以以确确定定函函数数名名与与代代码码间间

93、的的对对应应关关系系。因因此此,当当经经过过对对象象名名调调用用成成员员函函数数时时,只只能能够够是是调调用用对对象象本本身身的的成成员员,所所以以,这这种种情情况况可可采采用用静静态态联联编编实实现现。但但当当经经过过基基类类指指针针调调用用成成员员函函数数时时,由由于于基基类类指指针针可可以以指指向向该该基基类类的的不不同同派派生生类类对对象象,因因此此存存在在需需求求动动态态联联编编的的能能够够性性,但但详详细细能能否否运运用用动动态态联联编编,还还要看所调用的能否是虚函数。要看所调用的能否是虚函数。返回返回3.4 虚函数与多态性3.4.纯虚函数与笼统类纯虚函数与笼统类纯纯虚虚函函数数是

94、是在在基基类类中中只只声声明明虚虚函函数数而而不不给给出出详详细细的的函函数数定定义义体体,将将它它的的详详细细定定义义放放在在各各派派生生类类中中,称称此此虚虚函函数数为为纯纯虚虚函函数数。经经过过该该基基类类的的指指针针或或援援用用就就可可以以调调用用一一切切派派生生类类的的虚虚函函数数,基基类类只只是是用用于于承承继继,仅仅作作为为一一个个接接口,详细功能在派生类中实现。口,详细功能在派生类中实现。纯虚函数的声明如下:注:要放在基类的定义体中纯虚函数的声明如下:注:要放在基类的定义体中virtual函数原型函数原型=0;其其中中:函函数数原原型型的的格格式式同同前前面面所所学学格格式式一

95、一样样,要要包包括括函数前往值的类型、函数名、圆括号、形参及其类型等。函数前往值的类型、函数名、圆括号、形参及其类型等。声明了纯虚函数的类,称为笼统类。声明了纯虚函数的类,称为笼统类。运用纯虚函数时应留意:运用纯虚函数时应留意:1笼统类中可以有多个纯虚函数。笼统类中可以有多个纯虚函数。返回返回3.4 虚函数与多态性2不能声明笼统类的对象,但可以声明指向笼统类的指针变量和援用变量。3笼统类也可以定义其他非纯虚函数。4假设派生类中没有重新定义基类中的纯虚函数,那么在派生类中必需再将该虚函数声明为纯虚函数。5从笼统类可以派生出详细或笼统类,但不能从详细类派生出笼统类。6在一个复杂的类承继构造中,越上

96、层的类笼统程度越高,有时甚至无法给出某些成员函数的实现,显然,笼统类是一种特殊的类,它普通处于类承继构造的较外层。7引入笼统类的目的,主要是为了能将相关类组织在一个类承继构造中,并经过笼统类来为这些相关类提供一致的操作接口。返回返回3.4 虚函数与多态性【例【例3-16】设计一个笼统类设计一个笼统类shape,它表示具有外形的东,它表示具有外形的东西,表达了笼统的概念,在它下面可以派生出多种详细西,表达了笼统的概念,在它下面可以派生出多种详细外形,比如三角形、矩形。外形,比如三角形、矩形。#includeclassShapeprotected:doublex,y;public:voidset(

97、doublei,doublej)x=i;y=j;virtualvoidarea()=0;/声明纯虚函数声明纯虚函数;返回返回3.4 虚函数与多态性classTriangle:publicShapepublic:voidarea()cout三角形面积:0.5*x*yendl;classRectangle:publicShapepublic:voidarea()cout矩形面积:x*yset(5.1,10);p-area();p=&r;p-set(5.1,10);p-area();结果:三角形面积:25.5矩形面积:51返回返回3.5 静态成员 C+还有一种数据成员,称作“静态成员,静态成员是一切

98、对象公有的。静态成员有静态数据成员和静态函数成员之分。3.5.1静态数据成员阐明静态数据成员的语句格式是:static类型阐明符成员名;【例3-17】报名登记处登记每一位来访者的姓名,同时运用静态数据成员account自动产生一个流水号数,记入number中。返回返回3.5 静态成员#include#include/定义类marriedclassmarriedprivate:intnumber;/编号char*name;/姓名public:staticintglob;/定义静态数据成员globvoidset_mes(char*a);/set_mes函数阐明;返回返回3.5 静态成员/set_m

99、es函数定义voidmarried:set_mes(char*a)name=newcharstrlen(a)+1;strcpy(name,a);/用参数a的值修正私有变量。number=+glob;/glob加班后赋给numbercout编号:numberendl;intmarried:glob=0;/静态变量赋初始值0/主函数voidmain()/生成对象数组personmarriedperson100;返回返回3.5 静态成员inti;/部分变量icharstr8;/部分变量strcoutendl;for(i=0;i100;i+)/循环100次/读入姓名,存于strcoutstr;pers

100、oni.set_mes(str);/保管并显示coutendl;阐明:(1)不论一个类的对象有多少个,其静态数据成员也只需一个,由这些对象所共享,可被任何一个对象所访问。返回返回3.5 静态成员(2)在一个类的对象空间内,不包含静态成员的空间,所以静态成员所占空间不会随着对象的产生而分配,或随着对象的消逝而回收。(3)静态数据成员的存储空间的分配是在程序一开场运转时就被分配。并不是在程序运转过程中在某一函数内分配空间和初始化。(4)静态数据成员的赋值语句,既不属于任何类,也不属于包括主函数在内的任何函数,静态变量赋初值语句该当写在程序的全局区域中,并且必需指明其数据类型与所属的类名,并用如下格

101、式:类型类名:变量名=值;如:上例中的:intvisited:glob=0;返回返回3.5 静态成员(5)对于在类的public部分阐明的静态数据成员,可以不运用成员函数而直接访问,即使未定义类的对象,同样也可以直接访问,但在运用时也必需用类名指明所属的类,如在上例中的glob数据成员,可以在main函数体中直接访问,coutvisited:glob;而private和protected部分的静态成员只能经过类的成员函数访问。3.5.2静态成员函数静态成员函数的定义:static类型函数名形参函数体与静态数据成员一样,静态成员函数与类相联络,不与类的对象相联络,所以访问静态成员函数时,不需求对

102、象。如:返回返回3.5 静态成员#include“iostream.hclassobjcountprivate:staticintcount;public:objcount()count+;staticintget()returncount;intobjcount:count=0;voidmain()coutobjcount:get();objcounta,b,c,d,e,f;返回返回3.5 静态成员coutobjcount:get();counta.get();一个静态成员函数不与任何对象相联络,所以它不能对非静态成员进展默许访问。如:#include“iostream.hclassstud

103、entpublic:staticchar*sname()coutnoofstudentendl;returnname;返回返回3.5 静态成员protected:charname40;staticintnoofstudent;intstudent:noofstudent=0;voidfn()students;couts.sname()endl;/error/返回返回3.6 友元函数与友元类3.6.1友元函数友元函数C+提供一种允许外部类和函数存取类的私有成员和维护提供一种允许外部类和函数存取类的私有成员和维护成员的辅助方法,即将它们声明为一个给定类的友元成员的辅助方法,即将它们声明为一个给定类

104、的友元或友元函数,使其具有类成员函数的访问权限。但友或友元函数,使其具有类成员函数的访问权限。但友元本身不是类的成员,它不属于任何类。元本身不是类的成员,它不属于任何类。对于运用友元函数,有以下几点阐明:对于运用友元函数,有以下几点阐明:(1)为了在类的定义中对友元加以声明,只需在友元的称为了在类的定义中对友元加以声明,只需在友元的称号前加上关键字号前加上关键字friend即可。即可。(2)友元函数是能访问类的一切成员的普通函数,一个函友元函数是能访问类的一切成员的普通函数,一个函数可以是多个类的友元函数,只需在各个类中分别声明。数可以是多个类的友元函数,只需在各个类中分别声明。返回返回3.6

105、 友元函数与友元类 (3)将一个函数声明为某个类的友元函数的方法是在该类定义里提供一个以关键字friend开头的函数原型,友元函数的定义,可以在类的内部或外部,友元函数虽然是在类内进展声明,但它不是该类的成员函数,不属于任何类,在类外定义友元函数时,与普通函数的定义一样,不应在函数名前用类名加以限制,因此,友元函数不象成员函数那样在调用时运用对象名,友元函数要对类的成员进展访问,必需在参数表中显式指明要访问的对象。(4)一个类的友员函数与该类的类内成员函数一样,享有对该类一切成员的访问权。(5)友元函数的调用与普通函数的调用方式和原理一致。(6)C+不允许将构造函数、析构函数和虚函数声明为友元

106、函数。返回返回3.6 友元函数与友元类【例【例3-183-18】友元函数的定】友元函数的定义和运用方法。和运用方法。 #include “iostream.h #include “iostream.h class X1() class X1() private: private: int x; int x; public: public: X1(int i) x=i; X1(int i) x=i; int getx(); int getx(); friend friend void void sum(X1 sum(X1 &a, &a, X2 X2 &b); &b); /声声明明友友元元函数函数

107、 ; ;int X1:getx()int X1:getx() return x; return x;返回返回3.6 友元函数与友元类voidsum(X1&a,X1&b)/定义函数cout用友元函数求各和:a.x+b.xendl;/可以访问类的私有成员voidsum1(X1&a,X1&b)/定义普通函数cout用普通函数调用类公共接口函数求和:a.getx()+b.getx()endl;voidmain()X1m(1);X1n(2);sum(m,n);sum1(m,n);返回返回3.6 友元函数与友元类程序的执行结果为:用友元函数求各和:3用普通函数调用类公共接口函数求和:3返回返回3.6 友元

108、函数与友元类3.6.2友元类友元类友友元元类类是是在在多多个个类类之之间间建建立立一一种种访访问问机机制制,当当程程序序中中定定义义了了两两个个或或两两个个以以上上的的类类时时,假假设设一一个个类类将将本本人人阐阐明明为为另另一个类的友员类,其成员就可以被该类运用。一个类的友员类,其成员就可以被该类运用。定义友元类的语句格式为:定义友元类的语句格式为:friendclass类名;类名;其其中中:friend和和class是是关关键键字字,类类名名必必需需是是程程序序中中的的一一个已定义过的类。个已定义过的类。当当希希望望一一个个类类可可以以存存取取另另一一个个类类的的私私有有成成员员时时,可可

109、以以将将该该类类声声明明为为另另一一类类的的友友元元,友友元元类类的的一一切切成成员员函函数数都都可可视视为为该类的友元函数,能存取该类的私有成员和维护成员。该类的友元函数,能存取该类的私有成员和维护成员。返回返回3.6 友元函数与友元类如:将类B声明为类A的友元类的方法是在A类的定义中加上阐明:friendclassB;留意:友元关系不具有对称性。此外,友元关系不具有传送性,假设类B是类A的友元类,类C是类B的友元类,这并不隐含类C是类A的友元类。【例3-8】有两个类Cla_1和Cla_2。在类Cla_1的定义中阐明了友员类Cla_2。主函数中用它们生成了两个对象,然后对这两个对象的私有成员

110、进展访问。返回返回3.6 友元函数与友元类#include#include#include/定义类Cla_1classCla_1private:friendclassCla_2; /阐明友员类Cla_2char*name;intage;public:Cla_1(char*str,inti);返回返回3.6 友元函数与友元类/Cla_1的构造函数定义Cla_1:Cla_1(char*str,inti)name=str;/为类Cla_1的成员赋值age=i;/定义类Cla_2classCla_2/类Cla_2中并没有阐明Cla_1友员类public:voidshow(Cla_1x);返回返回3.6

111、 友元函数与友元类/Cla_2的show函数定义voidCla_2:show(Cla_1x)coutnn姓名:x.nameendl;coutn年龄:x.ageendl0&m1&d0&y300)year=y;voidmain()Tdate*pd;pd=newTdate(1,1,1998);/delete(pd);返回返回3.7 堆对象和对象数组阐明:阐明:1堆堆对对象象的的生生存存期期是是整整个个程程序序的的生生命命期期,所所以以只只需需程程序序运运转转终终了了时时,堆堆对对象象才才被被删删除除。这这一一点点与与普普通通的的部部分分对对象象的的生生命命期期不不同同,部部分分对对象象的的生生存存期

112、期开开场场于于函函数数体体的的执执行行,而终止于函数体执行终了。而终止于函数体执行终了。2堆对象用堆对象用delete来释放。来释放。返回返回3.7 堆对象和对象数组3.7.2对象数组对象数组一一个个数数组组的的类类型型除除了了可可以以为为根根本本的的数数据据类类型型外外,还还可可以以为为类类类类型型,那那么么这这时时,该该数数组组中中的的每每个个元元素素都都是是该该类类中中的一个对象,那么这种数组就是对象数组。的一个对象,那么这种数组就是对象数组。对象数组的定义方式:对象数组的定义方式:类名类名数组名数组名数组大小数组大小;【例例3-9】类类person是是阐阐明明人人员员的的信信息息构构造

113、造。用用person生生成成一一个个对对象象数数组组emp5,经经过过assignment将将人人员员信信息息填填入入,然后将它们显示出来。然后将它们显示出来。#include#include返回返回3.7 堆对象和对象数组classpersonprivate:char*name;/name指向信息串intage;/年龄public:person();/构造函数阐明person(); /析构函数阐明voidassignment(char*a,intb);/assignment函数阐明voidshow(); /show函数阐明;/构造函数定义person:person()返回返回3.7 堆对象和

114、对象数组name=newchar(0);/为name恳求存储空间,置为空age=-1;/为age赋初始值/析构函数定义person:person()deletename;/回收name空间/assignment函数定义voidperson:assignment(char*a,intb)name=newcharstrlen(a)+1;strcpy(name,a);/用参数a的值修正nameage=b;返回返回3.7 堆对象和对象数组/show函数定义voidperson:show()coutn姓名:name年龄:age;voidmain()/生成对象数组emp5personemp5;/给对象数组

115、赋值emp0.assignment(张立三,25);emp1.assignment(王冠之,28);emp2.assignment(王大成,35);emp3.assignment(英乐乐,21);emp4.assignment(“胡忠厚,26);返回返回3.7 堆对象和对象数组/显示empinti;for(i=0;i5;i+)empi.show();coutendl“-等运算符不能重等运算符不能重载。 表达式友元函数调用成员函数调用a+boperator+(a,b)a.operator+(b)a+operator+(a,0)a.operator+(0)-aoperator-(a)a.opera

116、tor-()返回返回3.9 模板与运用 模板就是使程序可以对不同类型的数据进展一样方式的处置。C+中的模板分为类模板和函数模板。3.9.1类模板阐明类模板的普通格式为:templateclass类模板名private:私有成员定义protected:维护成员定义public:公有成员定义;其中:(1)类型方式参数表可以包含根本数据类型,也可返回返回3.9 模板与运用以包含类类型,假设是类类型,那么须加前缀class。当参数有多个时,需用逗号隔开。(2)类模板中的成员函数的定义,可以放在类模板的定义体中此时与类中的成员函数的定义方法一致,也可以放在类模板的外部定义成员函数,此时成员函数的定义格式

117、如下:template函数值的前往类型类模板名:成员函数形参函数体其中:类模板名即是类模板中定义的称号;类型名表即是类模板定义中的类型方式参数表中的参数名。返回返回3.9 模板与运用(3)利用类模板定义的只是对类的描画,它本身还不是一个实真实在的类。因此是类模板。(4)要定义类模板的对象即实例,需求用以下格式的语句:类模板名对象名;【例3-22】定义类模板ABC,内含成员函数set和get。用ABC生成对象abc1和abc2。它们的数组元素数不同,显示的结果也不同。#include/定义类模板ABCtemplateclassABCprivate:TarrayI;/定义数组array返回返回3.

118、9 模板与运用public:voidset(intx)/定义成员函数setinti;for(i=0;iI;i+)/循环I次arrayi=x+i;/数组元素赋值voidget()/定义成员函数getcoutn数组元素总数为:Iendl;coutarrayI-1=arrayI-1endl;voidmain()/由模板ABC生成对象abc1返回返回3.9 模板与运用ABCabc1;abc1.set(0);/调用对象abc1.setabc1.get();/调用对象abc1.get/由模板ABC生成对象abc2ABCabc2;abc2.set(10);/调用对象abc2.setabc2.get();/调

119、用对象abc2.get以下是对上例中的成员函数定义体放于类模板外部定义的例如。【例3-23】定义模板ABC,内含成员函数set和get。用ABC生成对象abc1和abc2。它们的数组元素数不同,显示的结果也不同。返回返回3.9 模板与运用#include/定义类模板ABCtemplateclassABCprivate:TarrayI;/定义数组arraypublic:voidset(intx);/定义成员函数setvoidget();/定义成员函数get;templatevoidABC:set(intx)/定义成员函数setinti;返回返回3.9 模板与运用for(i=0;iI;i+)/循环

120、I次arrayi=x+i;/数组元素赋值templatevoidABC:get()coutn数组元素总数为:Iendl;coutarrayI-1=arrayI-1endl;voidmain()/由模板ABC生成对象abc1ABCabc1;abc1.set(0);/调用对象abc1.setabc1.get();/调用对象abc1.get返回返回3.9 模板与运用/由模板ABC生成对象abc2ABCabc2;abc2.set(10);/调用对象abc2.setabc2.get();/调用对象abc2.get类模板的运用方法可以总结为:(1)给出类模板的定义体。(2)在适当的位置创建一个类模板的实例

121、,即一个实真实在的类定义,同时创建该模板类的对象。(3)有了对象名,以后的运用就和普通类的对象是一致的。返回返回3.9 模板与运用3.9.2函数模板函数模板函函数数模模板板是是函函数数的的一一种种笼笼统统方方式式。由由于于C+中中的的数数据据类类型型很很多多,针针对对某某种种类类型型设设计计的的函函数数显显然然不不能能用用于于其其它它类类型型,因因此此对对于于同同一一个个功功能能的的要要求求,不不得得不不编编制制多多个个类类似似的的程序,比如求两个量中最小值的函数,类似的函数能够有:程序,比如求两个量中最小值的函数,类似的函数能够有:(1)求两个整型数据的最小值:求两个整型数据的最小值:int

122、min(intx,inty)(2)求两个单精度数据的最小值:求两个单精度数据的最小值:floatmin(floatx,floaty)(3)求求两两个个双双精精度度数数据据的的最最小小值值:doublemin(doublex,doubley)为为理理处处理理以以上上的的费费事事,C+引引入入了了函函数数模模板板的的概概念念。函函数模板就是用来处理一个模板生成多个函数的问题。数模板就是用来处理一个模板生成多个函数的问题。返回返回3.9 模板与运用定义函数模板的格式为:template函数前往值类型名函数模板名函数形参及类型函数体如:两个数最小值的函数模板定义如下:templateTmin(Tx,T

123、y)returnx;而而向向一一个个文文件件写写入入数数据据,可可以以运运用用其其put、write函数以及插入符函数以及插入符“。返回返回iostream的文件操作常用的函数的文件操作常用的函数函数原型函数原型阐明阐明get(char&ch)从文件中读取一个字符getline(char*pch,intcount,chardelim=n)从文件中读取多个字符,读取个数由参数count决议,参数delim是读取字符时指定的终了符read(char*pch,intcount)从文件中读取多个字符,读取个数由参数count决议put(charch)向文件写入一个字符write(constchar*p

124、ch,intcount)向文件写入多个字符,字符个数由count决议返回返回从文件的第一个字符字节开场顺序地处置到文件的最后一个字符字节,这种操作方式只能从文件的开场处依次顺序读写文件内容,而不能恣意读写文件内容。【例3-24】向文本文件中分别写入一个整数和一个字符串,然后再以读方式翻开该文件,从中读取相应的信息并显示到屏幕上。顺序文件的操作顺序文件的操作返回返回随机文件操作随机文件操作随机文件操作,即在文件中经过C+相关的函数挪动文件指针,并指向所要处置的字符字节。1在istream类中提供了3个操作读指针的成员函数:istream&istream:seekg(longpos);istrea

125、m&istream:seekg(longoff,dir);streamposistream:tellg();其中,pos为文件指针的绝对位置;off为文件指针的相对偏移量;dir为文件指针的参照位置,其值能够为:ios:cur文件指针的当前位置ios:beg文件开头ios:end文件尾tellg()函数没有参数,它前往一个long型值,用来表示从文件开场处到当前指针位置之间的字节数。返回返回2在ostream类中同样提供了3个操作写指针的成员函数:ostream&istream:seekp(longpos);ostream&istream:seekp(longoff,dir);streamposistream:tellp();这3个成员函数的含义与前面3个操作读指针成员函数的含义一样,只不过它们是用来操作写指针的。【例3-25】随机文件的读写操作。

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

最新文档


当前位置:首页 > 医学/心理学 > 基础医学

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