第3章:VC程序设计核心——类与对象ppt课件_第1页
第3章:VC程序设计核心——类与对象ppt课件_第2页
第3章:VC程序设计核心——类与对象ppt课件_第3页
第3章:VC程序设计核心——类与对象ppt课件_第4页
第3章:VC程序设计核心——类与对象ppt课件_第5页
已阅读5页,还剩105页未读 继续免费阅读

下载本文档

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

文档简介

.,1,第3章VC程序核心类与对象,教学要点本章内容主要包括面向对象程序设计特点、结构和类定义、类的成员变量和成员函数定义,类的封装性在类定义中的体现,利用继承性派生新的类,类的多态性。要求了解类的各种继承方式、抽象类的概念与使用。熟悉类的定义和如何实现类的封装性、继承性和多态性掌握构造函数和析构函数的调用特点、由类实例化对象的方法,熟练掌握通过虚函数、继承关系和指向基类的指针实现多态性的方法。,.,2,3.1面向对象程序设计特点3.2面向对象的基石类3.3对象3.4类的继承与派生3.5类的多态性,第3章目录,.,3,3.1面向对象程序设计特点,3.1.1抽象3.1.2封装3.1.3继承3.1.4多态3.1.5以VC作为面向对象程序设计的原因3.1.6*面向对象程序设计的优点,.,4,3.1.1抽象,抽象是指从具体的实例中抽取出来共同的性质并加以描述的过程,它忽略了一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。,.,5,3.1.2封装,封装指的是将方法和数据放于同一对象中,使得对数据的存取只能通过该对象本身的方法来进行。主要思想是将数据(数据成员)及处理这些数据的相应函数(成员函数)封装到类class中(C+的一种新的定义数据类型的方法),而使用类的变量则称为对象(object),在对象内,只有属于该对象的成员函数才可以存取该对象的数据成员。这样,其他函数就不会破坏到它的内容,从而起到保护和隐藏数据的效果。,.,6,3.1.3继承,继承是一种联结类与类之间的层次模型,它允许和鼓励类的重用,提供了一种明确表达共性的方法。一个新类可以从现有的类中派生,这个过程称为类继承继承性很好地解决了软件的可重用问题,.,7,3.1.4多态,多态性指的是同一消息被不同的对象接收后被解释为不同含义的能力,也就是一个接口名称具有多种功能。多态性语言具有语言灵活、抽象、行为共享、代码共享的优势,很好的解决了应用程序函数同名的问题。,.,8,3.1.5以VC作为面向对象程序设计的原因,1VC提供面向对象的完整语法与语义2.VC还是一种结构化的程序设计语言3VC中的MFC是理解面向对象语法与语义的最好平台,.,9,3.1.6面向对象程序设计的优点,面向对象编程的好处最明显的是使代码的可重用性大大提高,使程序员摆脱了重复性的劳动。面向对象编程中的对象比较独立,它给外界提供了统一的接口,当对象一旦建立,就可以重复使用。采用面向对象编程的好处就是代码的可扩充性。,.,10,3.2面向对象的基石类,3.2.1从结构到类3.2.2类的定义3.2.3类的属性成员变量3.2.4类的行为成员函数3.2.5类成员的访问控制3.2.6*类的深入理解,.,11,3.2.1从结构到类,1结构体VC不仅提供了大量预先定义的数据类型,而且还支持自定义的数据类型。结构就是把相互关联的一些基本数据类型的元素组成一个新的独立统一体。,.,12,【例3-1】定义一个职工Employee结构数据类型,它包括姓名、工资、地址、移动电话。structEmployeecharname9;floatsalary;charaddress40;charmobile12;,定义一个结构体,事实上是定义了一种数据类型,程序并不会给类型分配内存,内存分配是发生在结构体变量上,.,13,#includeiostream.h#includestring.hvoidmain()structEmployeeEmployeeA;strcpy(EmployeeA.name,灭绝师太);EmployeeA.salary=168.47;strcpy(EmployeeA.address,峨眉山上);strcpy(EmployeeA.mobile;coutEmployeeA.name已经领上工资了,其数目是EmployeeA.salaryendl;cout要想拜谒她,请到EmployeeA.address或直接传呼EmployeeA.mobileendl;,【例3-2】定义一个具体职工EmployeeA,并对该职工进行赋值。程序的主文件名为DefStru.cpp。,.,14,程序的运行结果是:灭绝师太已经领上工资了,其数目是168.47要想拜谒她,请到峨眉山上或直接传.,15,2类类是从一个个具体的事物中把共同特征抽取出来形成的一个概念,它反映了事物之间的共性在C+中,在类的定义中,不仅有反映事物属性的成员变量,还有反映属性操作的成员函数。类一种自定义数据类型。,.,16,3.2.2类的定义,在C+中类的定义方式为:class类名private:私有数据及成员函数;protected:保护数据及成员函数;public:公有数据及成员函数;;,.,17,class是类定义符,类名是一种标识符,它的命名规则与变量名的命名规则相同。一对花括号内是类的说明部分,说明该类的成员。类的成员包括成员变量和成员函数两部分。上述在类的成员变量和成员函数前面出现的关键字public(公有)、private(私有)或protected(保护)表示成员的访问属性。在类中声明的成员变量若不特别指明,都被视为私有类型。私有类型的数据只允许类本身声明的函数对其进行存取,而类外部的任何函数都不能访问。公有类型的成员可以被任何函数来访问,它们是类与外部的接口。,.,18,类的定义反映了对类的描述,定义一个类就是定义一种数据类型,把握类的定义首先要掌握类中包含反映事物属性的那些成员变量和反映事物操作的那些成员函数。【例3-3】定义一个职工TEmployee类,它包括姓名、工资、地址、移动电话数据成员和两个成员函数,分别实现输入职工数据和显示职工属性。,.,19,classTEmployeepublic:voidinput(char*name,floatsalary,char*address,char*mobile);voiddisplay();private:charm_name9;floatm_salary;charm_address40;charm_mobile12;,.,20,【例3-4】定义一个交通工具类TVehicle,它具有轮子个数、载重两个数据成员和三个成员函数,分别实现输入交通工具的轮子和载重、取轮子个数和载重。,classTVehiclepublic:voidInitialize(intwheels,floatweight);/交通工具的初始化intGetWheels(void);/取轮子个数floatGetWeight(void);/取载重private:intm_wheels;/轮子个数floatm_weight;/载重;,.,21,3.2.3类的属性成员变量,1类的普通成员变量类的普通成员变量指的是类的数据域的数据类型是基本数据类型如int、char、float等。例如前面定义的雇员类TEmployee,它的所有的数据域都是普通的成员变量。2类的对象成员变量类的对象成员变量指的是类的数据域的数据类型是其它的类,这些类可以是自定义的,也可以是一些类库中的类(如后面所说的MFC类库)。,.,22,【例3-5】在前面定义的职工TEmployee类中增加一个对象成员出生时间m_Birthday,它是MFC中的一个类CTime。,classTEmployeepublic:voidinput(char*name,floatsalary,char*address,char*mobile);private:charm_name9;CTimem_birthday;/定义对象成员m_birthday;,.,23,由于CTime类是MFC中的一个类,在使用该类库中的类时,必须在类的定义文件开始加上#include语句,并对VC当前开发的工程进行一些设置(点击菜单Projects|Setting,打开General选项卡,在MicrosoftFoundationClasses列表框中选择UseMFCinaSharedDLL)。,.,24,【例3-6】看看CTime类中的对象成员,体会微软软件开发师的杰作,体会对象成员的作用(这些代码在VisualStudiovc98mfcincludeafx.h头文件中)。,classCTimepublic:/ConstructorsstaticCTimePASCALGetCurrentTime();private:time_tm_time;/类的对象成员;,.,25,3类的静态成员变量,静态成员变量则不同于一般的类的成员变量。当一个类定义多个对象时,所有对象的静态成员变量占用同一个内存空间,也就是说静态成员变量对类的所有对象只有一份,不同的对象使用相同的成员变量。应用静态数据成员实现了数据的共享,使类的各个对象中可以进行消息的传递,同时静态数据成员不会破坏数据的封装性,有利于数据的安全通信。,.,26,从形式上看,静态成员变量是在一个类的成员变量定义前加上关键词static而构成的变量;从存储角度上看,静态成员变量在整个类上只保留一份,即该类的任何对象都共享该静态成员变量;从作用域来看,静态成员变量可看作类的公共变量;静态成员变量属于一个类而不属于该类的任何对象,所以,在类外调用静态成员变量时,必须要用“类名:”作为限定词。,.,27,【例3-7】一个含有类的静态成员变量的实例:某班级有三个同学A、B、C,该班有班费1000元。每个人都可以访问班级的班费,当A花去班费中的钱时,B、C得到的班费就少了,同样,当B花去班费中的钱时,A、C得到的班费就少了,因而应将班费设置为静态成员变量。它的特点是该类的每个对象都可以访问,属于类的公共变量。,.,28,classTStudentprivate:charm_Name6;staticintm_ClassMoney;/m_ClassMoney为静态成员变量,保存班费public:voidInitStudent(char*);voidExpendMoney(int);staticvoidShowMoney();intTStudent:m_ClassMoney=1000;/静态成员变量的初始化,.,29,【例3-8】了解应用程序类CWinApp公有的成员变量,CwinApp是Windows的一个应用程序类,它里面的一些公有的成员变量在程序中经常要使用。m_pszAppName:应用程序的名称(包含路径)。m_hInstance:应用程序的当前实例。m_hPrevInstance:应用程序的前一个实例。m_nCmdShow:应用程序主窗口的最初何显示方式(最大化、最小化等)。m_pMainWnd:指向应用程序主窗口的指针变量。m_pszExeName:应用程序的模块名称(不包含路径)。,.,30,3.2.4类的行为成员函数,当成员函数的函数体代码较短时,可以在定义类时直接定义成员函数,即在类内定义成员函数。但当成员函数函数体较复杂时,可以在类体外定义成员函数,但必须在类内对成员函数进行声明。,1类的普通成员函数,【例3-9】在前面定义的职工TEmployee类中有一个输入职工姓名、工资等属性的成员函数input(),通过它实现职工对象的初始化。另外还有一个显示职工信息的成员函数diplay(),这些函数在类体外进行定义:,.,31,classTEmployeepublic:voidinput(char*name,floatsalary,char*address,char*mobile);voiddisplay();private:charm_name9;voidTEmployee:input(char*name,floatsalary,char*address,char*mobile)strcpy(m_name,name);/字符串赋值必须通过字符串拷贝来实现m_salary=salary;strcpy(m_address,address);strcpy(m_mobile,mobile);,.,32,voidTEmployee:display()coutNameIsm_nameendl;coutSalaryIsm_salaryendl;coutAddressIsm_addressendl;coutmobileIsm_mobileendl;,说明:在类体外定义成员函数时必须使用作用域运算符“:”来指明成员函数所属的类,在类体内访问成员函数时,若未指明所属的类,则默认是这个类的成员函数,若要访问该类之外的其它类的成员函数,则必须指名该成员函数所属的类。,.,33,2类的静态成员函数,静态成员函数仅属于一个类而不属于该类的任何对象,因此它不通过对象直接调用,而是与类相联系的。静态成员函数中没有this指针,并且静态成员函数中只能访问静态成员变量,在类外调用静态成员函数时应使用以下方式:类名:静态成员函数名(参数列表);,.,34,【例3-10】一个含有静态成员函数的其使用。程序的主文件为StaticMember.cpp。,#includeiostream.h#includeclassTStudentprivate:charm_Name6;staticintm_ClassMoney;/m_ClassMoney为静态成员变量,保存班费public:voidInitStudent(char*);voidExpendMoney(int);staticvoidShowMoney();/静态成员函数;,.,35,intTStudent:m_ClassMoney=1000;/静态成员变量的初始化voidTStudent:InitStudent(charname)strcpy(m_Name,name);voidTStudent:ExpendMoney(intmoney)m_ClassMoney-=money;/班费为原先的减去花费的voidTStudent:ShowMoney()cout班费还剩余m_ClassMoneyendl;,.,36,voidmain()TStudentstu3;/定义三个学生stu0.InitStudent(marry);stu1.InitStudent(sunny);stu2.InitStudent(jahn);stu0.ExpendMoney(100);stu0.ShowMoney();/作用等同于TStudent:ShowMoney();stu1.ExpendMoney(100);stu1.ShowMoney();/作用等同于TStudent:ShowMoney();stu2.ExpendMoney(100);stu2.ShowMoney();/作用等同于TStudent:ShowMoney();,.,37,3类的虚成员函数,从形式上看,虚函数是在一个函数的定义前面加上关键词virtual而构成的函数。将函数定义为虚函数后,可以达到动态联编的效果,.,38,【例3-11】一个含有虚函数的类。,classTPoint/定义一个点类private:floatx,y;/x为横坐标,y为纵坐标public:voidPoint(floati,floatj)x=i;y=j;/构造函数virtualfloatarea()return0.0;/求面积的虚函数;,.,39,4MFC中类CString的常见操作,下面以在第二篇中常用的一个字符串类CString为例来说明类的成员函数功能。,CString的主要成员函数如下:(1)GetLength:返回CString对象中的字符数。(2)IsEmpty:测试一个CString对象是否空。(3)Empty:将一个字符数的长度强制为0。(4)GetAt:返回给定位置上的字符。(5)SetAt:设置给定位置上的字符。(6)Mid:提取一个字符串的中间部分。,.,40,请看下例:,(7)Left:提取一个字符串的左边部分。(8)Right:提取一个字符串的右边部分。(9)MakeUpper:将字符串中的所有字符转换为大写字符。(10)MakeLower:将字符串中的所有字符转换为小写字符。(11)Find:在一个较大的字符串中查找某一个字符串。(12)GetBuffer:返回一个指向CString对象的指针。,.,41,#includeiostream.h#includeafx.h/CString的头文件voidmain()CStringStr1=VC+实用教程;CStringStr2=出版商:电子工业出版社n;CStringStr3=Str1+Str2;CStringStr4=出版社;coutStr3.GetBuffer(0);/取字符串的首地址,【例3-12】CString的使用实例。该程序的主文件为StringTest.cpp,.,42,比较,c*c*c,if(Str1.Compare(Str2)/字符串比较cout0)/利用成员函数Find查找子串coutradius;MyCircle.set(radius);/正确,因为成员函数set()为公有成员cout该圆的面积为:MyCircle.area()endl;/正确,因为成员函数area()为公有成员/c.radius=3.3;/错误,类不能对私有成员直接进行访问,.,46,类的访问控制实质上反映了类对其成员的封装程度类的访问控制实质上反映了类对其成员的封装程度,当成员被声明为public时,它可以被外部类的对象访问,也可以被派生类的对象访问;当成员被声明为protected时,它不能被外部类的对象访问,但可以被派生类的对象访问;当成员被声明为private时,它既不能被外部类的对象访问,也不能被派生类的对象访问,只能被本类的成员函数访问。不管哪一种访问类型定义的成员,都可以被它所属类的成员函数所访问。,.,47,3.2.6*类的深入理解,1类是一种数据类型2类是一个代数系统3类是实现面向对象特性的载体,.,48,3.3对象,3.3.1对象的声明3.3.2对象的使用3.3.3对象的初始化构造函数3.3.4对象的撤消析构函数3.3.5*对象的深入理解,.,49,3.3.1对象的声明,inti;/声明一个整型对象i,该对象占有32个字节的空间charch;/声明一个字符对象ch,该对象占有1个字节的空间CTimeMyTime;/声明一个日期时间对象MyTimeCPointMyPoint;/声明个点对象MyPointCRectMyRect;/声明一个矩形对象MyRecct其中CTime、CPoint、CRect是VC中MFC类库中的一些通用类,这些类在实际设计程序时有着很重要的作用。,.,50,3.3.2对象的使用,当声明了对象后,就可以使用该对象所隶属的类的公有(在public部分定义的)成员变量和成员函数。对象的使用,关键是使用对象所属类的成员函数,即熟悉该类都有哪些常用的成员函数。,.,51,【例3-15】建立一个日期类,并且主函数中使用其公有的成员函。主文件为DefObject.cpp,#includeclassTDatepublic:voidSetDate(intyear,intmonth,intday)m_year=year;m_month=month;m_day=day;voidShowDate()coutThedateism_year-m_month-m_day成员函数),它是隐式调用,即在一个新对象建立时(包含两种情况:一种是在对象的声明语句中,另一种是用new函数建立新的动态对象时),该对象所隶属类的构造函数自动被调用。,.,54,注:,当类中不给出类的构造函数时,系统将自动给出默认的构造函数,这个构造函数没有参数,而且函数体为空构造函数不允许有返回值,也不许定义函数的返回值类型构造函数可以重载,即可以定义多个参数个数不同或类型不同的构造函数。,.,55,3.3.4对象的撤消析构函数,析构函数是在撤消对象时进行收尾工作的工具。它的功能是:在对象被撤消时,对该对象所占的空间进行释放。当类中没有给出析构函数时,系统将自动生成一个缺省的构造函数。当撤消对象时(对象的生存期结束或通过delete函数释放动态对象),系统会自动调用析构函数。析构函数不允许定义函数的返回值类型,定义析构函数时不能指定任何形式的参数,而且析构函数也不能重载,即析构函数在一个类中只能有一个。,.,56,【例3-16】一个包含构造函数和析构函数的例子。程序的主文件为ConstructorExam.cpp。,#include#includeclassExlprivate:intx;public:Exl()coutEx1类的对象建立,其构造函数被调用n;Exl()coutEx1类的对象撤消,其析构函数被调用n;voidsetdata(inti)x=i*2;/在类中定义成员函数setdata()voidprint();/类Exl定义结束,.,57,classEx2inty;public:Ex2()coutEx2类的对象建立,其构造函数被调用n;Ex2()coutEx2类的对象撤消,其析构函数被调用n;voidsetdata(intj)y=j*j;voidprint();/类Ex2定义结束voidEx2:print()coutclassEx2:setw(6)yn;/成员函数print()定义结束,.,58,voidmain()Exls;Ex2t;s.setdata(5);s.print();t.setdata(5);t.print();,程序运行结果为:Ex1类的对象建立,其构造函数被调用Ex2类的对象建立,其构造函数被调用classExl:10classEx2:25Ex2类的对象撤消,其析构函数被调用Ex1类的对象撤消,其析构函数被调用,.,59,3.3.5*对象的深入理解,1对象就是变量2对象是封装了属性和行为的基本单位3对象是一个有限状态自动机,.,60,3.4类的继承与派生,3.4.1类与类之间的四种关系3.4.2继承的概念3.4.3派生类的声明3.4.4基类成员的访问控制3.4.5派生与继承的应用,.,61,3.4.1类与类之间的四种关系,是封装了事物属性和方法的同类对象的集合。,类,UML(unifiedmodellanguage,统一建模语言)认为,类之间主要存在四种关系。,1关联(Association)关系,关联关系表示两个类之间存在某种语义上的联系,即与该关联连接的类的对象之间具有一定的语义连接关系,该关系表达了类之间的一种相关性。,.,62,2依赖(Dependency)关系,依赖关系描述的是两个类之间的语义上的连接关系,它是一种“Use-A”关系。假设有两个元素A与B,如果修改元素A的定义可能会引起对另一个元素B的定义的修改,则称元素B依赖于A。,3聚合(Aggregation)关系,聚合关系是一种“Has-A”关系,它体现的是类之间的一种整体与部分的关系。例如汽车包括四个轮子和一个发动机等。,.,63,4泛化(Generalization)关系,泛化关系是一种“Is-A”关系,它描述的是类之间的“一般”与“特殊”的关系。具有共同特性的元素可以抽象为一般类,并通过增加其内涵,进一步抽象成特殊类。该关系可以将类组成一种有层次、有分类的结构。例如:狗是一种哺乳动物,哺乳动物是一种动物等。在VC中建立类之间的泛化关系采用的是继承机制。,.,64,3.4.2继承的概念,继承是描述类与类之间关系的一个概念,它提高了代码的重用性,使得程序更加模块化,便于程序更简单而又准确地描述事物。继承关系可以用由派生类指向基类的箭头表示,如图3.4所示:,.,65,3.4.3派生类的声明,单继承中派生类的声明格式为:class派生类类名:访问控制限定符基类名;其中访问控制限定符号可以是public(公有派生)、protected(保护派生)和private(私有派生)。,【例3-17】一个派生类的声明实例。如果交通工具用前面讲的类TVehicle来抽象表示,汽车用类TCar来抽象表示的话,那么汽车从交通工具继承而来(或交通工具派生汽车的)的语义表示成C+语言的语法描述为:,.,66,classTCar:publicTVehiclepublic:voidInitialize(intwheels,floatweight,intpassenger=4);GetPassenger(void);private:intm_passenger;,.,67,3.4.4基类成员的访问控制,派生类对基类成员的访问不仅取决于基类成员声明的访问控属性,还取决于派生类对基类的“继承程度”。继承程度有有三种:公有(public)、受保护(protected)和私有(private)类型的继承。,我们可以根据下表中的继承成员访问控制规则来决定使用哪种访问方式更合理,不同的访问控制,决定了基类可以被派生类所访问的“开放”程度。,.,68,表3.1继承成员访问控制规则,.,69,【例3-19】一个使用类的继承实例。主文件为InheritTest.cpp。,3.4.5派生与继承的应用,#includeiostream.hclassTVehicle/交通工具类的声明public:voidInitialize(intwheels,floatweight);intGetWheels(void)returnm_wheels;floatGetWeight(void)returnm_weight;private:intm_wheels;/轮子floatm_weight;/载重;,.,70,voidTVehicle:Initialize(intwheels,floatweight)m_wheels=wheels;m_weight=weight;classTCar:publicTVehicle/汽车类从交通工具类公有派生public:voidInitialize(intwheels,floatweight,intpassenger);intGetPassenger(void)returnm_passenger;private:intm_passenger;/乘客数;voidTCar:Initialize(intwheels,floatweight,intpassenger=4)TVehicle:Initialize(wheels,weight);/调用父类的函数进行初始化,.,71,voidmain()TVehicleVehicleInstance;/声明一个交通工具对象VehicleInstanceTCarCarInstance;/声明一个汽车对象CarInstanceVehicleInstance.Initialize(4,6);/初始化交通工具cout交通工具轮子的个数是:VehicleInstance.GetWheels()endl;cout交通工具轮子的载重为:VehicleInstance.GetWeight()endl;CarInstance.Initialize(1,2);/初始化汽车/调用从基类继承而来的函数GetWheels等cout汽车的轮子、载重和乘客数为:m_passenger=passenger;CarInstance.GetWheels()tCarInstance.GetWeight()t;coutCarInstance.GetPassenger()endl;/调用派生类新增的函数GetPassenger,.,72,程序运行结果为:交通工具轮子的个数是:4交通工具轮子的载重为:6汽车的轮子、载重和乘客数为:124,.,73,3.5类的多态性,3.5.1多态性概述3.5.2多态性的类型3.5.3编译时多态性的两种方式3.5.4运行时多态性的实现条件3.5.5纯虚函数与抽象类3.5.6*使用虚函数的好处习题,.,74,3.5.1多态性概述,在VC中,这种同一符号或名字在不同情况下表现为不同的语义现象称为多态性。,严格地讲,在VC中,不同的类可以有语义相同的函数,这些函数在概念上是相似的,但对应各自的类来说,其实现是不同的,因而对象在接收到同样的函数调用时所引发的行为有可能是不同的,这一功能称为多态性。直观地讲就是“一个名称,多个函数”。,.,75,3.5.2多态性的类型,程序设计的多态性有两种形式:编译时的多态性和运行时的多态性。,多态性的实现与联编有关。将一个函数的调用与其相应的函数体代码相链接的过程,称为函数联编。C+中有两种类型的联编:静态联编和动态联编。,.,76,静态联编是指在调用同名函数(即重载函数)时,编译器将根据调用时所使用的实际参数个数、类型的不同确定应该调用哪一个函数的实现,它是在程序编译阶段就确定下来的多态性。静态联编通过使用重载(overload)机制来获得,重载机制包括函数重载和运算符重载。,动态联编是在程序的运行阶段根据当时的情况来确定应该调用哪个同名函数的实现。动态联编主要通过继承与虚函数两者结合来实现的。,.,77,静态联编的代码链接工作是在编译时完成的,所以运行时不需要额外时间来做这些工作,因此静态联编的代码效率较高。动态联编将函数调用的链接时间后移到代码执行的时候,这必然使函数调用时间开销增加,效率降低,但大大增强了语言的灵活性。程序员可以根据实际情况需要来决定使用哪一种联编方式,从而兼顾代码的高效性和灵活性。,静态联编与动态联编各有优缺点:,.,78,3.5.3编译时多态性的两种形式-函数与运算符重载,1函数重载两个以上的函数,取相同的函数名称,但是形参个数或者类型不同,编译器根据实参和形参的类型和个数选择最匹配的函数,来自动地确定调用哪一个函数,这就是函数的重载。函数重载包括普通成员函数重载和类的成员函数重载,下面给出相应的实例。,【例3-20】普通函数重载的例子。给函数add()定义多个函数来实现,该函数的功能是求和,可以求两个整型数之和,两个浮点数之和,也可以求三个双精度浮点数之和,每种实现对应着一个函数体,这些函数的名字相同,但是函数的参数个数或类型不同,这就是函数重载。在VC+中,函数可以共享同一个名字,只是这些同名函数的参数表有所不同。程序的主文件为Function.cpp。,.,79,#includeintadd(inta,intb)returna+b;floatadd(floatx,floaty)returnx+y;voidadd(doublea,doubleb,doublec)couta+b+cendl;voidmain()intm=1,n=2;floatx=1.2,y=2.3;doublea=2.0,b=3.0,c=2.5;coutadd(m,n)endl;/因为m与n为int型,故调用的是第一个add函数coutadd(x,y)endl;/因为x与y为float型,故调用的是第二个add函数add(a,b,c);/因为a、b、c为double,且包含三个参数型,故调用的是第三个add函数,.,80,从程序的运行结果来看add(m,n)是调用了intadd(inta,intb)函数;add(x,y)调用了函数floatadd(floatx,floaty);add(a,b,c)调用了voidadd(doublea,doubleb,doublec)函数。这些函数可以同名,同名的函数为重载函数。,程序的运行结果是:33.57.5,.,81,注意:(1)函数重载时,函数声明必须能互相区别,即函数参数个数或参数类型必须有所不同,如果只有函数的返回值不同,不能区分重载函数;(2)函数功能一般相类似,本质上有区别的函数,最好不要重载;(3)不同参数传递方式无法区别重载函数。例如:intadd(inta,intb);intadd(int这两个函数不能作为重载函数,编译时会出错。,.,82,【例3-21】类的成员函数重载的例子。类的成员函数重载的最典型的情况在类的构造函数的重载。MFC类库中有一个点类CPoint,查看MSDN的说明,知道它有多个构造函数,下面为其中的构造函数的原型说明:CPoint(intinitX,intinitY);CPoint(POINTinitPt);CPoint(SIZEinitSize);,.,83,2运算符重载,运算符重载本质上就是函数的重载,是函数重载的特殊形式(函数名为运算符号),VC语言中允许程序员重新定义运算符的语义,这一机制称为运算符重载。,与函数重载类似,运算符重载就是当运算符的操作对象不同时,运算符呈现出不同的运算状态。运算符函数有两种形式:一种是在类中定义的运算符成员函数,即类成员运算符;另一种是在类之外定义的运算符函数,通常使用友元形式,即友元运算符。,.,84,类的运算符重载的定义形式类型类名:operator重载运算符(参数表)/运算符函数体,【例3-22】用类的成员函数重载运算符“+”实现复数相加的例子,重载运算符“=”实现两个复数是否相等的判断。程序的主文件为Operator.cpp,.,85,#includeiostream.hclassTComplex/定义数学上的复数类public:TComplex(floatreal=0,floatimage=0);/缺省构造函数TComplex(constTComplex,.,86,TComplex:TComplex(floatreal,floatimage)/缺省的构造函数的实现m_real=real;m_image=image;TComplex:TComplex(constTComplex,.,87,voidTComplex:ShowValue()/显示复数值代码cout0)cout+m_imagei;if(m_image0)coutm_imagei;coutendl;voidmain()TComplexComplex1(6,8);/将复数Complex1设置为4+5iTComplexComplex2(-2,-3);/将复数Complex1设置为-2-3i,调用缺省构造函数完成TComplexComplex3(Complex1);/用Complex1初始化Complex3,调用拷贝构造函数完成后,这两个复数相等TComplexComplex4,Complex5;/将复数Complex4,Complex5设置为0,调用缺省构造函数完成,.,88,Complex1.ShowValue();/显示复数complex1Complex2.ShowValue();Complex3.ShowValue();Complex4.ShowValue();Complex5.ShowValue();Complex4=Complex1+Complex2;/以运算符形式调用复数的相加,和两个数的普通加法形式一样Complex4.ShowValue();Complex5=Complex1.operator+(Complex2);/以函数形式调用复数的相加,注意在运算符的前面必须加上关键字operatorComplex5.ShowValue();if(Complex4=Complex5)/利用重载的运算符=判断两个复数是否相等coutComplex4和Complex5相等n;elsecoutComplex4和Complex5不相等n;,.,89,程序运行结果:6+8i-2-3i6+8i004+5i4+5iComplex4和Complex5相等,运算符重载增加了程序的灵活性,但运算符重载不能改变运算符的基本功能,也不能改变运算符的优先级和结合性,运算符重载不能使用缺省参数。,.,90,3.5.4运行时多态性的实现条件,1定义超载(overriding)函数要使程序出现运行时的多态性,必须有继承关系。在类的层次结构中,定义完全相同的函数原型,但这些类层次中同名函数的实现代码却不同。这些不仅同名而且同原型的函数称作函数的超载(override)。,2声明超载函数为虚函数,1、声明虚拟函数classTAnimalprivate:charm_strName10;public:virtualvoidRoar()cout并不知道哪个类的动物在叫endl;/此函数说明为虚函数;2、使用继承,.,91,3通过基类指针来访问,一般情况下,指向一种类型对象的指针不允许指向另一种类型的对象。但指向基类的指针可以指向派生类对象,【例3-23】虚函数和多态性的应用实例。程序中定义了鸟类、狗类和老虎类,我们知道,不论是鸟、狗还是老虎,他们都会叫,但它们的叫声是完全不同的。如果这三个类都有一个叫Roar()的成员函数,那么在这三个类的Roar函数的实现代码肯定是不一样的。在TAnimal类的Roar函数之前加上Virtual,使其成为虚函数,然后再通过指向基类TAnimal的指针来访问,就可实现运行时的多态性。程序的主文件为DynaPoly.cpp。,.,92,#include#include#includeclassTAnimalprivate:charm_strName10;public:virtualvoidRoar()cout并不知道哪个类的动物在叫endl;voidSetName(char*strName)strcpy(m_strName,strName);char*GetName()returnm_strName;classTBird:publicTAnimal/定义鸟类TBirdpublic:TBird()SetName(Bird);voidRoar()coutTheGetName()isRoaringisitagoodsinger?n;,.,93,classTDog:publicTAnimal/定义狗类TDogpublic:TDog()SetName(Dog);voidRoar()coutTheGetName()isRoaringisitboring?n;classTTiger:publicTAnimal/定义老虎类TTigerpublic:TTiger()SetName(Tiger);voidRoar()coutTheGetName()“isRoaringisitfrightful?n;,.,94,voidmain()TAnimalanimal;TBirdbird;TDogdog;TTigertiger;coutRoar();pAnimal=,.,95,程序运行结果为:以下为静态联编-并不知道哪个类的动物在叫TheBirdisRoaring.isitagoodsinger?TheDogisRoaring.isitboring?TheTigerisRoaring.isitfrightful?以下为动态联编-TheBirdisRoaring.isitagoodsinger?TheDogisRoaring.isitboring?TheTigerisRoaring.isitfrightful?,.,96,通过指针的方式来访问虚函数是动态联编,倘若把派生类的Roar函数前的virtual去掉,则变为静态联编。自己把去掉virtual的程序运行一下,其运行结果为:以下为静态联编-并不知道哪个类的动物在叫TheBirdisRoaring.isitagoodsinger?TheDogisRoaring.isitboring?TheTigerisRoaring.isitfrightful?,.,97,以下为动态联编-并不知道哪个类的动物在叫并不知道哪个类的动物在叫并不知道哪个类的动物在叫可见要实现动态联编,必须将基类的Roar定义成为虚函数,这种情形称为函数的超载(Override)或同名覆盖,.,98,3.5.5纯虚函数与抽象类,纯虚函数的定义,在基类中只声明虚函数而不给出具体的定义,将它的具体定义放在各派生类中,称此虚函数为纯虚函数(purevirtualfunction)。声明了纯虚函数的类,称为抽象类(abstractclass)。纯虚拟函数的声明形式如下:virtual函数类型函数原型(参数表)=0;将虚拟函数的原型设置为0,该虚函数即

温馨提示

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

评论

0/150

提交评论