资源预览内容
第1页 / 共110页
第2页 / 共110页
第3页 / 共110页
第4页 / 共110页
第5页 / 共110页
第6页 / 共110页
第7页 / 共110页
第8页 / 共110页
第9页 / 共110页
第10页 / 共110页
亲,该文档总共110页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
第第3章章 VC程序核心程序核心类与对象类与对象 教学要点教学要点本本章章内内容容主主要要包包括括面面向向对对象象程程序序设设计计特特点点、结结构构和和类类定定义义、类类的的成成员员变变量量和和成成员员函函数数定定义义,类类的的封封装装性性在在类类定定义义中中的的体体现现,利利用用继继承承性性派生新的类,类的派生新的类,类的多态性多态性。要求了解类的各种要求了解类的各种继承方式、抽象类继承方式、抽象类的概念与使用。熟悉类的定义的概念与使用。熟悉类的定义和如何和如何实现类的封装性、继承性和多态性实现类的封装性、继承性和多态性掌握掌握构造函数和析构函数构造函数和析构函数的调用特点、由类实例化对象的方法,熟的调用特点、由类实例化对象的方法,熟练掌握通过练掌握通过虚函数、继承关系和指向基类的指针实现多态性的方法。虚函数、继承关系和指向基类的指针实现多态性的方法。 1课堂优质3.1 3.1 面向对象程序设计特点面向对象程序设计特点 3.2 3.2 面向对象的基石面向对象的基石类类3.3 3.3 对象对象 3.4 3.4 类的继承与派生类的继承与派生 3.5 3.5 类的多态性类的多态性 第第3章目录章目录2课堂优质3.1面向对象程序设计特点面向对象程序设计特点3.1.13.1.1抽象抽象3.1.23.1.2封装封装3.1.33.1.3继承继承3.1.43.1.4多态多态3.1.53.1.5以以VCVC作为面向对象程序设计的原因作为面向对象程序设计的原因3.1.6 3.1.6 * * 面向对象程序设计的优点面向对象程序设计的优点3课堂优质3.1.1 抽象抽象 抽抽象象是是指指从从具具体体的的实实例例中中抽抽取取出出来来共共同同的的性性质质并并加加以以描描述述的的过过程程,它它忽忽略略了了一一个个主主题题中中与与当当前前目目标标无无关关的的那那些些方方面面,以以便便更更充充分分地地注注意意与与当当前目标有关的方面。前目标有关的方面。 4课堂优质3.1.2 封装封装 封装指的是将封装指的是将方法和数据放于同一对象中方法和数据放于同一对象中,使,使得对数据的存取只能通过该对象本身的方法来进行。得对数据的存取只能通过该对象本身的方法来进行。 主主要要思思想想是是将将数数据据(数数据据成成员员)及及处处理理这这些些数数据据的的相相应应函函数数(成成员员函函数数)封封装装到到类类classclass中中(C+C+的的一一种种新新的的定定义义数数据据类类型型的的方方法法),而而使使用用类类的的变变量量则则称称为为对对象象(objectobject),在在对对象象内内,只只有有属属于于该该对对象象的的成成员员函函数数才才可可以以存存取取该该对对象象的的数数据据成成员员。这这样样,其其他他函函数数就就不不会会破破坏坏到到它它的的内内容容,从从而而起起到到保保护和隐藏数据的效果。护和隐藏数据的效果。5课堂优质3.1.3 继承继承 E继承继承是一种联结类与类之间的层次模型,它允许是一种联结类与类之间的层次模型,它允许和鼓励类的重用,提供了一种明确表达共性的方法。和鼓励类的重用,提供了一种明确表达共性的方法。E一个新类可以从现有的类中派生,这个过程称为一个新类可以从现有的类中派生,这个过程称为类继承类继承 E继承性很好地解决了软件的可重用问题继承性很好地解决了软件的可重用问题 6课堂优质 3.1.4多态多态E多态性指的是同一消息被不同的对象接收后被解多态性指的是同一消息被不同的对象接收后被解释为不同含义的能力,也就是释为不同含义的能力,也就是一个接口名称具有多一个接口名称具有多种功能。种功能。 E多态性语言具有多态性语言具有语言灵活、抽象、行为共享、代语言灵活、抽象、行为共享、代码共享码共享的优势,很好的解决了应用程序函数同名的的优势,很好的解决了应用程序函数同名的问题。问题。7课堂优质3.1.5 以以VC作为面向对象作为面向对象程序设计的原因程序设计的原因E1 1VCVC提供面向对象的完整语法与语义提供面向对象的完整语法与语义 E2. 2. VCVC还是一种结构化的程序设计语言还是一种结构化的程序设计语言E3 3VCVC中的中的MFCMFC是理解面向对象语法与语义是理解面向对象语法与语义 的最好平台的最好平台8课堂优质3.1.6 面向对象程序面向对象程序设计的优点设计的优点 面向对象编程的好处最明显的是使面向对象编程的好处最明显的是使代码的可重用代码的可重用性大大提高性大大提高, ,使程序员摆脱了重复性的劳动。使程序员摆脱了重复性的劳动。 面向对象编程中的对象比较独立,面向对象编程中的对象比较独立,它给外界提供它给外界提供了统一的接口了统一的接口,当对象一旦建立,就可以重复使用,当对象一旦建立,就可以重复使用 。 采用面向对象编程的好处就是采用面向对象编程的好处就是代码的可扩充性。代码的可扩充性。 9课堂优质3.2面向对象的基石面向对象的基石类类3.2.1 3.2.1 从结构到类从结构到类 3.2.2 3.2.2 类的定义类的定义 3.2.3 3.2.3 类的属性类的属性成员变量成员变量3.2.4 3.2.4 类的行为类的行为成员函数成员函数 3.2.5 3.2.5 类成员的访问控制类成员的访问控制 3.2.6 3.2.6 * * 类的深入理解类的深入理解10课堂优质3.2.1 从结构到类从结构到类 1结构体结构体 VCVC不不仅仅提提供供了了大大量量预预先先定定义义的的数数据据类类型型,而且还支持自定义的数据类型。而且还支持自定义的数据类型。结结构构就就是是把把相相互互关关联联的的一一些些基基本本数数据据类类型的元素组成一个新的独立统一体。型的元素组成一个新的独立统一体。 11课堂优质 【例例3-1】 定定义义一一个个职职工工EmployeeEmployee结结构构数数据据类类型型,它它包包括姓名、工资、地址、移动电话。括姓名、工资、地址、移动电话。struct Employeestruct Employee char name9;char name9;float salary;float salary;char address40;char address40;char mobile12; char mobile12; ;定义一个结构体,事实上是定义了一种数据类型,程序并定义一个结构体,事实上是定义了一种数据类型,程序并不会给类型分配内存,内存分配是发生在结构体变量上不会给类型分配内存,内存分配是发生在结构体变量上12课堂优质# #include iostream.hinclude iostream.h#include string.h#include string.hvoid main()void main() struct Employee EmployeeA;struct Employee EmployeeA;strcpy(EmployeeA.name,strcpy(EmployeeA.name,灭绝师太灭绝师太););EmployeeA.salary=168.47;EmployeeA.salary=168.47;strcpy(EmployeeA.address,strcpy(EmployeeA.address,峨眉山上峨眉山上););strcpy(EmployeeA.mobile,13688667755);strcpy(EmployeeA.mobile,13688667755);cout cout EmployeeA.nameEmployeeA.name已已经经领领上上工工资资了了, ,其其数数目目是是 EmployeeA.salaryendl;EmployeeA.salaryendl;coutcout要要想想拜拜谒谒她她,请请到到 EmployeeA.addressEmployeeA.address或或直直接接传呼传呼 EmployeeA.mobileendl;EmployeeA.mobileendl; 【例【例3-2】 定义一个具体职工定义一个具体职工EmployeeAEmployeeA,并对该职工进行并对该职工进行赋值。程序的主文件名为赋值。程序的主文件名为DefStru.cppDefStru.cpp。13课堂优质程序的运行结果是:程序的运行结果是:灭绝师太已经领上工资了灭绝师太已经领上工资了, ,其数目是其数目是168.47168.47要想拜谒她,请到峨眉山上或直接传呼要想拜谒她,请到峨眉山上或直接传呼1368866775513688667755 14课堂优质2类类E类类是是从从一一个个个个具具体体的的事事物物中中把把共共同同特特征征抽抽取取出出来来形成的一个概念,形成的一个概念,它反映了事物之间的共性它反映了事物之间的共性 E在在C+C+中,在类的定义中,不仅有中,在类的定义中,不仅有反映事物属性反映事物属性的成员变量,还有反映属性操作的成员函数。的成员变量,还有反映属性操作的成员函数。E类一种自定义数据类型类一种自定义数据类型 。15课堂优质3.2.2 类的定义类的定义 在在C+中类的定义方式为:中类的定义方式为:class class 类名类名 private:private: 私有数据及成员函数;私有数据及成员函数;protected:protected: 保护数据及成员函数;保护数据及成员函数;public:public: 公有数据及成员函数;公有数据及成员函数;;16课堂优质Eclassclass是类定义符是类定义符,类名是一种标识符,它的命,类名是一种标识符,它的命名规则与变量名的命名规则相同。名规则与变量名的命名规则相同。一对花括号内一对花括号内是类的说明部分,说明该类的成员是类的说明部分,说明该类的成员。类的成员包。类的成员包括括成员变量和成员函数两部分。成员变量和成员函数两部分。E上述在类的成员变量和成员函数前面出现的关键上述在类的成员变量和成员函数前面出现的关键字字publicpublic(公有)、公有)、privateprivate(私有)或私有)或protectedprotected(保护)表示成员的访问属性保护)表示成员的访问属性。在类中在类中声明的成员变量若不特别指明,都被视为私有类声明的成员变量若不特别指明,都被视为私有类型型。私有类型的数据只允许类本身声明的函数对。私有类型的数据只允许类本身声明的函数对其进行存取,而类外部的任何函数都不能访问。其进行存取,而类外部的任何函数都不能访问。公有类型的成员可以被任何函数来访问,它们是公有类型的成员可以被任何函数来访问,它们是类与外部的接口。类与外部的接口。 17课堂优质E类的定义反映了对类的描述类的定义反映了对类的描述,定义一个类,定义一个类就是定义一种数据类型,把握类的定义首就是定义一种数据类型,把握类的定义首先要掌握类中包含反映事物属性的那些成先要掌握类中包含反映事物属性的那些成员变量和反映事物操作的那些成员函数。员变量和反映事物操作的那些成员函数。 E【例例3-33-3】 定定义义一个一个职职工工TEmployeeTEmployee类类,它,它包括姓名、工包括姓名、工资资、地址、移、地址、移动电话动电话数据成数据成员员和两个成和两个成员员函数,分函数,分别实现输别实现输入入职职工数工数据和据和显显示示职职工属性。工属性。 18课堂优质class TEmployeeclass TEmployee public:public:void void input(char input(char *name,float *name,float salary,char salary,char *address,char *mobile); *address,char *mobile); void display();void display();private:private:char m_name9;char m_name9;float m_salary;float m_salary;char m_address40;char m_address40;char m_mobile12; char m_mobile12; ;19课堂优质【例例3-43-4】 定义一个交通工具类定义一个交通工具类TVehicleTVehicle,它具有轮子它具有轮子个数、载重两个数据成员和三个成员函数,分别实现输个数、载重两个数据成员和三个成员函数,分别实现输入交通工具的轮子和载重、取轮子个数和载重。入交通工具的轮子和载重、取轮子个数和载重。 class TVehicleclass TVehicle public :public :void void Initialize(int Initialize(int wheels,float wheels,float weight);/weight);/交交通通工工具具的的初始化初始化int GetWheels(void);/int GetWheels(void);/取轮子个数取轮子个数float GetWeight(void);/float GetWeight(void);/取载重取载重private:private:int m_wheels; /int m_wheels; /轮子个数轮子个数float m_weight;/ float m_weight;/ 载重载重;20课堂优质3.2.3 类的属性类的属性成员变量成员变量E1类的普通成员变量类的普通成员变量 类的普通成员变量指的是类的数据域的数据类的普通成员变量指的是类的数据域的数据类型是基本数据类型类型是基本数据类型如如int、char、float等。例等。例如前面定义的雇员类如前面定义的雇员类TEmployee,它的所有的数它的所有的数据域都是普通的成员变量。据域都是普通的成员变量。E2类的对象成员变量类的对象成员变量 类的对象成员变量指的是类的数据域的数据类的对象成员变量指的是类的数据域的数据类型是其它的类类型是其它的类,这些类可以是自定义的,也可,这些类可以是自定义的,也可以是一些类库中的类(如后面所说的以是一些类库中的类(如后面所说的MFC类库)。类库)。 21课堂优质【例例3-5】 在前面定义的职工在前面定义的职工TEmployeeTEmployee类中增加一类中增加一个对象成员出生时间个对象成员出生时间m_Birthdaym_Birthday,它是它是MFCMFC中的一个中的一个类类CTimeCTime。class TEmployeeclass TEmployee public:public:void void input(char input(char *name,float *name,float salary,char salary,char *address,char *mobile); *address,char *mobile); private:private:char m_name9;char m_name9;CTime m_birthday;/CTime m_birthday;/定义对象成员定义对象成员m_birthdaym_birthday;22课堂优质 由由于于CTime类类是是MFC中中的的一一个个类类,在在使使用用该该类类库库中中的的类类时时,必必须须在在类类的的定定义义文文件件开开始始加加上上#include 语语句句,并并对对VC当当前前开开发发的的工工程程进进行行一一些些设设置置(点点击击菜菜单单Projects|Setting,打打开开General选选 项项 卡卡 , 在在 Microsoft Foundation Classes列列表表框框中中选选择择Use MFC in a Shared DLL)。)。 23课堂优质【例【例3-6】 看看看看CTimeCTime类中的对象成员,体会微软类中的对象成员,体会微软软件开发师的杰作,体会对象成员的作用(这些代软件开发师的杰作,体会对象成员的作用(这些代码在码在Visual Studiovc98mfcincludeafx.hVisual Studiovc98mfcincludeafx.h头文头文件中)。件中)。 class CTimeclass CTime public:public:/ Constructors/ Constructorsstatic CTime PASCAL GetCurrentTime();static CTime PASCAL GetCurrentTime(); private:private:time_t m_time; /time_t m_time; /类的对象成员类的对象成员;24课堂优质3类的静态成员变量E静态成员变量则不同于一般的类的成员变量。静态成员变量则不同于一般的类的成员变量。当一个类定义多个对象时,所有对象的静态成当一个类定义多个对象时,所有对象的静态成员变量占用同一个内存空间,也就是说员变量占用同一个内存空间,也就是说静态成静态成员变量对类的所有对象只有一份,不同的对象员变量对类的所有对象只有一份,不同的对象使用相同的成员变量使用相同的成员变量 。E应用静态数据成员实现了数据的共享应用静态数据成员实现了数据的共享,使类的,使类的各个对象中可以进行消息的传递,同时静态数各个对象中可以进行消息的传递,同时静态数据成员不会破坏数据的封装性,有利于数据的据成员不会破坏数据的封装性,有利于数据的安全通信。安全通信。 25课堂优质E从形式上看,静态成员变量是在一个类的成员变量从形式上看,静态成员变量是在一个类的成员变量定义前加上关键词定义前加上关键词staticstatic而构成的变量;而构成的变量;E从存储角度上看,静态成员变量在整个类上只保留从存储角度上看,静态成员变量在整个类上只保留一份,即一份,即该类的任何对象都共享该静态成员变量;该类的任何对象都共享该静态成员变量;E从作用域来看,从作用域来看,静态成员变量可看作类的公共变静态成员变量可看作类的公共变量;量;E静态成员变量属于一个类而不属于该类的任何对象,静态成员变量属于一个类而不属于该类的任何对象,所以,所以,在类外调用静态成员变量时,必须要用在类外调用静态成员变量时,必须要用“类名类名:”作为限定词。作为限定词。26课堂优质【例【例3-73-7】 一个含有类的静态成员变量的实例一个含有类的静态成员变量的实例: :某班某班级有三个同学级有三个同学A A、B B、C C,该班有班费该班有班费10001000元。每个人元。每个人都可以访问班级的班费,当都可以访问班级的班费,当A A花去班费中的钱时,花去班费中的钱时,B B、C C得到的班费就少了,同样,当得到的班费就少了,同样,当B B花去班费中的钱时,花去班费中的钱时,A A、C C得到的班费就少了,因而应将班费设置为静态成得到的班费就少了,因而应将班费设置为静态成员变量。它的特点是该类的每个对象都可以访问,属员变量。它的特点是该类的每个对象都可以访问,属于类的公共变量。于类的公共变量。 27课堂优质class TStudentclass TStudent private:private:char m_Name6;char m_Name6;static int m_ClassMoney;static int m_ClassMoney;/m_ClassMoney/m_ClassMoney为静态成员变量,保存班费为静态成员变量,保存班费public:public:void InitStudent(char *);void InitStudent(char *);void ExpendMoney(int); void ExpendMoney(int); static void ShowMoney();static void ShowMoney();int TStudent:m_ClassMoney=1000; int TStudent:m_ClassMoney=1000; /静态成员变量的初始化静态成员变量的初始化 28课堂优质【例3-8】了解应用程序类CWinAppCWinApp公有的成员变量 CwinApp CwinApp是是WindowsWindows的一个应用程序类,它里面的一些公有的一个应用程序类,它里面的一些公有的成员变量在程序中经常要使用。的成员变量在程序中经常要使用。Em_pszAppNamem_pszAppName:应用程序的名称(包含路径)。应用程序的名称(包含路径)。Em_hInstancem_hInstance:应用程序的当前实例。应用程序的当前实例。Em_hPrevInstancem_hPrevInstance:应用程序的前一个实例。应用程序的前一个实例。Em_nCmdShowm_nCmdShow:应用程序主窗口的最初何显示方式(最大化、应用程序主窗口的最初何显示方式(最大化、最小化等)。最小化等)。Em_pMainWndm_pMainWnd:指向应用程序主窗口的指针变量。指向应用程序主窗口的指针变量。Em_pszExeNamem_pszExeName:应用程序的模块名称(不包含路径)。应用程序的模块名称(不包含路径)。29课堂优质3.2.4 类的行为类的行为成员函数成员函数 当成员函数的函数体代码较短时,可以在定义当成员函数的函数体代码较短时,可以在定义类时直接定义成员函数,类时直接定义成员函数,即在类内定义成员函数即在类内定义成员函数。但当成员函数函数体较复杂时,可以但当成员函数函数体较复杂时,可以在类体外定义在类体外定义成员函数,但必须在类内对成员函数进行声明。成员函数,但必须在类内对成员函数进行声明。 1 1类的普通成员函数类的普通成员函数 【例【例3-9】 在前面定义的职工在前面定义的职工TEmployeeTEmployee类中有一个输入类中有一个输入职工姓名、工资等属性的成员函数职工姓名、工资等属性的成员函数input()input(),通过它实现职通过它实现职工对象的初始化。另外还有一个显示职工信息的成员函数工对象的初始化。另外还有一个显示职工信息的成员函数diplaydiplay()(),这些函数在类体外进行定义:这些函数在类体外进行定义: 30课堂优质class TEmployeeclass TEmployeepublic:public:void input(char *name,float salary,char *address,void input(char *name,float salary,char *address, char *mobile); char *mobile); void display();void display();private:private:char m_name9;char m_name9;void TEmployee:input(char *name,float salary,char *address,void TEmployee:input(char *name,float salary,char *address, char *mobile) char *mobile) strcpy(m_name,name); /strcpy(m_name,name); /字符串赋值必须通过字符串拷贝来实现字符串赋值必须通过字符串拷贝来实现m_salary=salary;m_salary=salary;strcpy(m_address,address);strcpy(m_address,address);strcpy(m_mobile,mobile);strcpy(m_mobile,mobile); 31课堂优质void TEmployee:display()void TEmployee:display() coutName Is m_nameendl;coutName Is m_nameendl;coutSalary Is m_salaryendl;coutSalary Is m_salaryendl;coutAddress Is m_addressendl;coutAddress Is m_addressendl;coutmobile Is m_mobileendl;coutmobile Is m_mobileendl; 说明说明: :在类体外定义成员函数时必须使用在类体外定义成员函数时必须使用作用域运算符作用域运算符“:”来指明成员函数所属的类,在类体内访问成员函数时,来指明成员函数所属的类,在类体内访问成员函数时,若未指明所属的类,则默认是这个类的成员函数,若要访问若未指明所属的类,则默认是这个类的成员函数,若要访问该类之外的其它类的成员函数,则必须指名该成员函数所属该类之外的其它类的成员函数,则必须指名该成员函数所属的类的类。32课堂优质2 2类的静态成员函数类的静态成员函数 静态成员函数仅属于一个类而不属于该类的静态成员函数仅属于一个类而不属于该类的任何对象任何对象, ,因此它不通过对象直接调用,而是与因此它不通过对象直接调用,而是与类相联系的。类相联系的。静态成员函数中没有静态成员函数中没有thisthis指针,并指针,并且静态成员函数中只能访问静态成员变量,且静态成员函数中只能访问静态成员变量,在类在类外调用静态成员函数时应使用以下方式:外调用静态成员函数时应使用以下方式: 类名类名:静态成员函数名静态成员函数名( (参数列表参数列表););33课堂优质 【例【例3-10】一个含有静态成员函数的其使用。程】一个含有静态成员函数的其使用。程序的主文件为序的主文件为StaticMember.cppStaticMember.cpp。 # #include iostream.hinclude iostream.h#include #include class TStudentclass TStudent private:private:char m_Name6;char m_Name6;static int m_ClassMoney;static int m_ClassMoney; /m_ClassMoney /m_ClassMoney为静态成员变量,保存班费为静态成员变量,保存班费public:public:void InitStudent(char *);void InitStudent(char *);void ExpendMoney(int); void ExpendMoney(int); static void ShowMoney();/static void ShowMoney();/静态成员函数静态成员函数;34课堂优质int TStudent:m_ClassMoney=1000; /int TStudent:m_ClassMoney=1000; /静态成员变量的初始化静态成员变量的初始化void TStudent:InitStudent(char name)void TStudent:InitStudent(char name) strcpy(m_Name,name);strcpy(m_Name,name); void TStudent:ExpendMoney(int money)void TStudent:ExpendMoney(int money) m_ClassMoney-=money; /m_ClassMoney-=money; /班费为原先的减去花费的班费为原先的减去花费的 void TStudent:ShowMoney() void TStudent:ShowMoney() coutcout班费还剩余班费还剩余 m_ClassMoneyendl; m_ClassMoneyendl; 35课堂优质void main()void main() TStudent stu3;/TStudent stu3;/定义三个学生定义三个学生stu0.InitStudent(marry);stu0.InitStudent(marry); stu1.InitStudent(sunny); stu1.InitStudent(sunny);stu2.InitStudent(jahn);stu2.InitStudent(jahn);stu0.ExpendMoney(100);stu0.ExpendMoney(100);stu0.ShowMoney();/stu0.ShowMoney();/作用等同于作用等同于TStudent:ShowMoney();TStudent:ShowMoney();stu1.ExpendMoney(100);stu1.ExpendMoney(100);stu1.ShowMoney();/stu1.ShowMoney();/作用等同于作用等同于TStudent:ShowMoney();TStudent:ShowMoney();stu2.ExpendMoney(100);stu2.ExpendMoney(100);stu2.ShowMoney();/stu2.ShowMoney();/作用等同于作用等同于TStudent:ShowMoney();TStudent:ShowMoney(); 36课堂优质3 3类的虚成员函数类的虚成员函数 从从形形式式上上看看,虚虚函函数数是是在在一一个个函函数数的的定定义义前前面面加加上上关关键键词词virtualvirtual而而构构成成的的函函数数。将将函函数数定定义义为为虚虚函函数数后后,可可以以达达到到动动态态联联编编的效果的效果 37课堂优质【例【例3-113-11】一个含有虚函数的类。】一个含有虚函数的类。class TPoint /class TPoint /定义一个点类定义一个点类 private :private :float x, y ; /xfloat x, y ; /x为横坐标为横坐标, ,y y为纵坐标为纵坐标public :public :void Point (float i , float j) void Point (float i , float j) x=i ; y=j; /x=i ; y=j; /构造函数构造函数virtual float area ( ) virtual float area ( ) return 0.0 ; / return 0.0 ; /求面积的虚函数求面积的虚函数; ; 38课堂优质4 4MFCMFC中类中类CStringCString的常见操作的常见操作 下下面面以以在在第第二二篇篇中中常常用用的的一一个个字字符符串串类类CStringCString为例来说明类的成员函数功能。为例来说明类的成员函数功能。CString的主要成员函数如下:的主要成员函数如下:C(1)GetLength:返回返回CString对象中的字符数。对象中的字符数。C(2)IsEmpty:测试一个测试一个CString对象是否空。对象是否空。C(3)Empty:将一个字符数的长度强制为将一个字符数的长度强制为0。C(4)GetAt:返回给定位置上的字符。返回给定位置上的字符。C(5)SetAt:设置给定位置上的字符。设置给定位置上的字符。C(6) MidMid:提取一个字符串的中间部分。提取一个字符串的中间部分。39课堂优质请看下例:请看下例:C(7) Left:提取一个字符串的左边部分。提取一个字符串的左边部分。C(8) Right:提取一个字符串的右边部分。提取一个字符串的右边部分。C(9) MakeUpper:将将字字符符串串中中的的所所有有字字符符转转换换为为大大写字符。写字符。C(10) MakeLower:将将字字符符串串中中的的所所有有字字符符转转换换为为小小写字符。写字符。C(11) Find:在在一一个个较较大大的的字字符符串串中中查查找找某某一一个个字字符符串。串。C(12) GetBuffer:返回一个指向返回一个指向CString对象的指针。对象的指针。 40课堂优质# #include iostream.hinclude iostream.h#include afx.h /CString#include afx.h /CString的头文件的头文件void main()void main() CString Str1=VC+CString Str1=VC+实用教程实用教程; CString Str2=CString Str2=出版商:电子工业出版社出版商:电子工业出版社 n;n; CString Str3=Str1+Str2; CString Str3=Str1+Str2; CString Str4= CString Str4=出版社出版社;coutStr3.GetBuffer(0);/coutStr3.GetBuffer(0);/取字符串的首地址取字符串的首地址 【例【例3-123-12】CStringCString的使用实例。该程序的主文的使用实例。该程序的主文件为件为StringTest.cppStringTest.cpp41课堂优质比比较较c*c*cif(Str1.Compare(Str2) /if(Str1.Compare(Str2) /字符串比较字符串比较coutcout字符串字符串Str1Str1与与Str2Str2不相同不相同 n;n;Str3=Str1.Left(2)+Str1.Right(4); /Str3=Str1.Left(2)+Str1.Right(4); /提取字符串提取字符串coutStr3.GetBuffer(0)endl;coutStr3.GetBuffer(0)0) /if(Str2.Find(Str4)0) /利用成员函数利用成员函数FindFind查找子串查找子串coutcout在在Str2Str2中找到子串中找到子串Str4n;Str4n; 程序运行结果为:程序运行结果为:VC+VC+实用教程出版商:电子工业出版社实用教程出版商:电子工业出版社字符串字符串Str1Str1与与Str2Str2不相同不相同VCVC教程教程在在Str2Str2中找到子串中找到子串Str4Str442课堂优质3.2.5 类成员的访问控制类成员的访问控制 类的主要作用是类的主要作用是实现对数据和操作的封装实现对数据和操作的封装 对类的成员访问必须有所限制对类的成员访问必须有所限制,根据访问权限不,根据访问权限不同可将类的访问控制分为同可将类的访问控制分为公有(公有(publicpublic)、)、受保受保护(护(protectedprotected)和私有(和私有(privateprivate)三种方式三种方式 如果未加说明,则默认的访问控制为如果未加说明,则默认的访问控制为privateprivate。 请看下例:请看下例:43课堂优质【例【例3-133-13】访问控制实例。该程序的主文件为】访问控制实例。该程序的主文件为AccessControl.cpp AccessControl.cpp # #include include #define PI 3.14159#define PI 3.14159class circleclass circlepublic: void set(int r) radius = r ; float area();private :float radius;float circle:area() return (PI*radius*radius); 44课堂优质void main()void main() int radius ;int radius ; circle MyCircle ; circle MyCircle ;coutcoutradius;cinradius;MyCircle.set(radius); MyCircle.set(radius); /正确,因为成员函数正确,因为成员函数set()set()为公有成员为公有成员coutcout该圆的面积为:该圆的面积为:MyCircle.area()endl; MyCircle.area()endl; /正确,因为成员函数正确,因为成员函数area()area()为公有成员为公有成员/c.radius=3.3; c.radius=3.3; / / 错误,类不能对私有成员直接进行访问错误,类不能对私有成员直接进行访问 45课堂优质类的访问控制实质上反映了类对其成员的封装程度类类的访问控制实质上反映了类对其成员的封装程度类的访问控制实质上反映了类对其成员的封装程度的访问控制实质上反映了类对其成员的封装程度 E当成员被声明为当成员被声明为public时,它可以被外部类的对象访问,时,它可以被外部类的对象访问,也可以被派生类的对象访问;也可以被派生类的对象访问;E当成员被声明为当成员被声明为protected时,它不能被外部类的对象时,它不能被外部类的对象访问,但可以被派生类的对象访问;访问,但可以被派生类的对象访问;E当成员被声明为当成员被声明为private时,它既不能被外部类的对象时,它既不能被外部类的对象访问,也不能被派生类的对象访问,只能被本类的成员函访问,也不能被派生类的对象访问,只能被本类的成员函数访问。数访问。E不管哪一种访问类型定义的成员,都可以被它所属类的不管哪一种访问类型定义的成员,都可以被它所属类的成员函数所访问。成员函数所访问。 46课堂优质3.2.6 * 类的深入理解类的深入理解 E1类是一种数据类型类是一种数据类型E2类是一个代数系统类是一个代数系统E3类是实现面向对象特性的载体类是实现面向对象特性的载体47课堂优质3.3 对象对象 3.3.1 3.3.1 对象的声明对象的声明 3.3.2 3.3.2 对象的使用对象的使用3.3.3 3.3.3 对象的初始化对象的初始化构造函数构造函数3.3.4 3.3.4 对象的撤消对象的撤消析构函数析构函数 3.3.53.3.5 * * 对象的深入理解对象的深入理解 48课堂优质3.3.1 对象的声明对象的声明 int i;/int i;/声明一个整型对象声明一个整型对象i i,该对象占有该对象占有3232个字节的空间个字节的空间 char ch;/char ch;/声明一个字符对象声明一个字符对象chch,该对象占有该对象占有1 1个字节的空间个字节的空间 CTime MyTime;/CTime MyTime;/声明一个日期时间对象声明一个日期时间对象MyTimeMyTimeCPoint MyPoint;/CPoint MyPoint;/声明个点对象声明个点对象MyPointMyPointCRect MyRect;/CRect MyRect;/声明一个矩形对象声明一个矩形对象MyRecctMyRecct 其中其中CTimeCTime、CPointCPoint、CRectCRect是是VCVC中中MFCMFC类库中的一些通用类库中的一些通用类,这些类在实际设计程序时有着很重要的作用。类,这些类在实际设计程序时有着很重要的作用。 49课堂优质3.3.2 对象的使用对象的使用E当声明了对象后,就可以使用该对象所隶当声明了对象后,就可以使用该对象所隶属的类的公有(在属的类的公有(在public部分定义的)成部分定义的)成员变量和成员函数。员变量和成员函数。 E对象的使用,对象的使用,关键是使用对象所属类的成关键是使用对象所属类的成员函数员函数,即熟悉该类都有哪些常用的成员,即熟悉该类都有哪些常用的成员函数。函数。 50课堂优质【例例3-15】建立一个日期类,并且主函数中使用】建立一个日期类,并且主函数中使用其公有的成员函其公有的成员函。主文件为。主文件为DefObject.cpp#include class TDatepublic:void SetDate(int year,int month,int day) m_year=year ;m_month=month ; m_day=day ; void ShowDate( ) cout The date is m_year-m_month-m_day成员函数),它是隐式调用,成员函数),它是隐式调用,即在一个新对象建立时(包含两种情况:一种是在对象的声明语句即在一个新对象建立时(包含两种情况:一种是在对象的声明语句中,另一种是用中,另一种是用new函数建立新的动态对象时),该对象所隶属类函数建立新的动态对象时),该对象所隶属类的构造函数自动被调用。的构造函数自动被调用。 53课堂优质注:注:E当类中不给出类的构造函数时,当类中不给出类的构造函数时,系统将自系统将自动给出默认的构造函数动给出默认的构造函数,这个构造函数没,这个构造函数没有参数,而且函数体为空有参数,而且函数体为空 E构造函数不允许有返回值构造函数不允许有返回值,也不许定义函,也不许定义函数的返回值类型数的返回值类型 E构构造造函函数数可可以以重重载载,即即可可以以定定义义多多个个参参数数个数不同或类型不同的构造函数。个数不同或类型不同的构造函数。54课堂优质3.3.4 对象的撤消对象的撤消析构函数析构函数 E析构函数是在撤消对象时进行收尾工作的工具析构函数是在撤消对象时进行收尾工作的工具。E它的它的功能功能是:在对象被撤消时,对该对象所占的空是:在对象被撤消时,对该对象所占的空间进行释放。间进行释放。E当当类类中中没没有有给给出出析析构构函函数数时时,系系统统将将自自动动生生成成一一个个缺省的构造函数。缺省的构造函数。E当撤消对象时当撤消对象时(对象的生存期结束或通过(对象的生存期结束或通过deletedelete函函数释放动态对象),数释放动态对象),系统会自动调用析构函数系统会自动调用析构函数。 E析构函数不允许定义函数的返回值类型,析构函数不允许定义函数的返回值类型,定义析构定义析构函数时不能指定任何形式的参数,而且析构函数也函数时不能指定任何形式的参数,而且析构函数也不能重载,即析构函数在一个类中只能有一个。不能重载,即析构函数在一个类中只能有一个。55课堂优质【例【例3-16】一个包含构造函数和析构函数的例子。】一个包含构造函数和析构函数的例子。程序的主文件为程序的主文件为ConstructorExam.cppConstructorExam.cpp。# #include include #include #include class Exlclass Exl private:private:int x;int x;public:public:Exl() Exl() coutEx1 coutEx1 类类的的对对象象建建立立,其其构构造造函函数数被被调调用用 n; n; Exl() Exl() coutEx1coutEx1类类的的对对象象撤撤消消,其其析析构构函函数数被被调调用用 n; n; void void setdata(int setdata(int i) i) x=i*2; x=i*2; /在在类类中中定定义义成成员员函函数数setdata()setdata()void print();void print();/;/类类ExlExl定义结束定义结束56课堂优质class Ex2class Ex2 int y;int y;public:public:Ex2() Ex2() coutEx2 coutEx2 类类的的对对象象建建立立,其其构构造造函函数数被被调调用用 n; n; Ex2() Ex2() coutEx2coutEx2类类的的对对象象撤撤消消,其其析析构构函函数数被被调调用用 n; n; void setdata(int j) y=j*j;void setdata(int j) y=j*j;void print();void print();/;/类类Ex2Ex2定义结束定义结束void Ex2:print()void Ex2:print() coutclass Ex2: setw(6)y n;coutclass Ex2: setw(6)y n;/成员函数成员函数print()print()定义结束定义结束57课堂优质void main( )void main( ) Exl s;Exl s;Ex2 t;Ex2 t;s.setdata(5);s.setdata(5);s.print( );s.print( );t.setdata(5);t.setdata(5);t.print( );t.print( ); 程序运行结果为:程序运行结果为:Ex1 Ex1 类类的的对对象象建建立立,其其构构造造函函数被调用数被调用Ex2 Ex2 类类的的对对象象建建立立,其其构构造造函函数被调用数被调用class Exl: 10class Exl: 10class Ex2: 25class Ex2: 25Ex2Ex2类类的的对对象象撤撤消消,其其析析构构函函数被调用数被调用Ex1Ex1类类的的对对象象撤撤消消,其其析析构构函函数被调用数被调用58课堂优质3.3.5 * 对象的深入理解对象的深入理解 1对象就是变量对象就是变量 2对象是封装了属性和行为的基本单位对象是封装了属性和行为的基本单位 3对象是一个有限状态自动机对象是一个有限状态自动机 59课堂优质3.4 类的继承与派生类的继承与派生 3.4.1 3.4.1 类与类之间的四种关系类与类之间的四种关系3.4.2 3.4.2 继承的概念继承的概念 3.4.3 3.4.3 派生类的声明派生类的声明 3.4.4 3.4.4 基类成员的访问控制基类成员的访问控制 3.4.5 3.4.5 派生与继承的应用派生与继承的应用 60课堂优质 3.4.1 类与类之间的四种关系类与类之间的四种关系 是封装了事物属性和方法的同类对象的集合。是封装了事物属性和方法的同类对象的集合。 类类UML(unified model language,统统一一建建模模语语言言)认认为为,类类之间主要存在四种关系。之间主要存在四种关系。1 1关联关联( (Association)Association)关系关系 关联关系表示两个类之间存在某种语义上的联系,关联关系表示两个类之间存在某种语义上的联系, 即与该关联连接的类的对象之间具有一定的语义连接关系,即与该关联连接的类的对象之间具有一定的语义连接关系,该关系表达了类之间的一种相关性。该关系表达了类之间的一种相关性。61课堂优质2依赖(依赖(Dependency)关系关系 依赖关系描述的是两个类之间的语义上的连接关依赖关系描述的是两个类之间的语义上的连接关系,它是一种系,它是一种“Use-A”关系。假设有两个元素关系。假设有两个元素A与与B,如果修改元素如果修改元素A的定义可能会引起对另一个元素的定义可能会引起对另一个元素B的定的定义的修改,则称元素义的修改,则称元素B依赖于依赖于A。 3聚合(聚合(Aggregation)关系关系 聚合关系是一种聚合关系是一种“Has-A”关系,它体现的是类关系,它体现的是类之间的一种整体与部分的关系。例如汽车包括四个之间的一种整体与部分的关系。例如汽车包括四个轮子和一个发动机等。轮子和一个发动机等。 62课堂优质4泛化泛化(Generalization )关系关系泛泛化化关关系系是是一一种种“Is-A”关关系系,它它描描述述的的是是类类之之间间的的“一一般般”与与“特特殊殊”的的关关系系。具具有有共共同同特特性性的的元元素素可可以以抽抽象象为为一一般般类类,并并通通过过增增加加其其内内涵涵,进进一一步步抽抽象象成成特特殊殊类类。该该关关系系可可以以将将类类组组成成一一种种有有层层次次、有有分分类类的的结结构构。例例如如:狗狗是是一一种种哺哺乳乳动动物物,哺哺乳乳动动物物是是一一种种动动物物等等。在在VC中中建建立立类类之之间间的的泛泛化化关关系系采采用用的的是是继继承机制。承机制。63课堂优质3.4.2 继承的概念继承的概念 继继承承是是描描述述类类与与类类之之间间关关系系的的一一个个概概念念,它它提提高高了了代代码码的的重重用用性性,使使得得程程序序更更加加模模块块化化,便便于于程程序序更更简单而又准确地描述事物。简单而又准确地描述事物。继承关系可以用由派生类指向基类的箭头表示,继承关系可以用由派生类指向基类的箭头表示,如图如图3.4所示:所示:交通工具交通工具飞机飞机汽车汽车火车火车轿车轿车卡车卡车面包车面包车64课堂优质3.4.3 派生类的声明派生类的声明 单继承中派生类的声明格式为:单继承中派生类的声明格式为: class class 派生类类名:访问控制限定符派生类类名:访问控制限定符 基类名基类名; ;其其中中访访问问控控制制限限定定符符号号可可以以是是public(公公有有派派生生)、protected(保护派生)和保护派生)和private(私有派生)私有派生) 。 【例例3-17】一一个个派派生生类类的的声声明明实实例例。如如果果交交通通工工具具用用前前面面讲讲的的类类TVehicle来来抽抽象象表表示示,汽汽车车用用类类TCar来来抽抽象象表表示示的的话话,那那么么汽汽车车从从交交通通工工具具继继承承而而来来(或或交交通通工工具具派派生汽车的)的语义表示成生汽车的)的语义表示成C+语言的语法描述为:语言的语法描述为:65课堂优质class TCar: public TVehicleclass TCar: public TVehicle public:public:void Initialize(int wheels,float weight,int passenger=4);void Initialize(int wheels,float weight,int passenger=4);GetPassenger(void);GetPassenger(void);private:private:int m_passenger;int m_passenger;66课堂优质3.4.4 基类成员的访问控制基类成员的访问控制 派生类派生类对基类成员的访问不仅取决于对基类成员的访问不仅取决于基类成员声明的访问控属性,还取决于派生基类成员声明的访问控属性,还取决于派生类对基类的类对基类的“继承程度继承程度”。继承程度有有三。继承程度有有三种:种:公有(公有(publicpublic)、)、受保护受保护(protectedprotected)和和私有(私有(privateprivate)类型的继类型的继承。承。 我我们们可可以以根根据据下下表表中中的的继继承承成成员员访访问问控控制制规规则则来来决决定定使使用用哪哪种种访访问问方方式式更更合合理理,不不同同的的访访问问控控制制,决决定定了了基基类类可可以以被被派派生生类所访问的类所访问的“开放开放”程度。程度。 67课堂优质表表3.1 继承成员访问控制规则继承成员访问控制规则继承访问控制继承访问控制基类成员访问控制基类成员访问控制在派生类中的访问控制在派生类中的访问控制publicpublicpublicprotectedprotectedprivate不可访问protectedpublicprotectedprotectedprotectedprivate不可访问privatepublicprivateprotectedprivateprivate不可访问68课堂优质【例例3-19】一个使用类的继承】一个使用类的继承实例。主文件为实例。主文件为InheritTest.cpp。3.4.5 派生与继承的应用派生与继承的应用 # #include iostream.hinclude iostream.hclass TVehicle /class TVehicle /交通工具类的声明交通工具类的声明 public :public :void Initialize(int wheels,float weight);void Initialize(int wheels,float weight);int GetWheels(void) return m_wheels;int GetWheels(void) return m_wheels;float GetWeight(void)return m_weight;float GetWeight(void)return m_weight;private:private:int m_wheels; /int m_wheels; /轮子轮子float m_weight; /float m_weight; /载重载重;69课堂优质void TVehicle:Initialize(int wheels,float weight)void TVehicle:Initialize(int wheels,float weight) m_wheels=wheels;m_wheels=wheels; m_weight=weight; m_weight=weight; class TCar: public TVehicle/class TCar: public TVehicle/汽车类从交通工具类公有派生汽车类从交通工具类公有派生 public:public:void Initialize(int wheels,float weight,int passenger);void Initialize(int wheels,float weight,int passenger);int GetPassenger(void) return m_passenger;int GetPassenger(void) return m_passenger;private:private:int m_passenger; /int m_passenger; /乘客数乘客数;void TCar:Initialize(int wheels,float weight,int passenger=4)void TCar:Initialize(int wheels,float weight,int passenger=4) TVehicle:Initialize(wheels,weight); TVehicle:Initialize(wheels,weight); /调调用用父父类类的的函函数数进进行行初初始始化化70课堂优质void main()void main() TVehicle VehicleInstance; /TVehicle VehicleInstance; /声明一个交通工具对象声明一个交通工具对象VehicleInstanceVehicleInstanceTCar CarInstance; /TCar CarInstance; /声明一个汽车对象声明一个汽车对象CarInstanceCarInstanceVehicleInstance.Initialize(4,6); /VehicleInstance.Initialize(4,6); /初始化交通工具初始化交通工具coutcout交通工具轮子的个数是:交通工具轮子的个数是:VehicleInstance.GetWheels()endl;VehicleInstance.GetWheels()endl;coutcout交通工具轮子的载重为:交通工具轮子的载重为:VehicleInstance.GetWeight()endl;VehicleInstance.GetWeight()endl;CarInstance.Initialize(1,2); /CarInstance.Initialize(1,2); /初始化汽车初始化汽车/调用从基类继承而来的函数调用从基类继承而来的函数GetWheelsGetWheels等等 coutcout汽车的轮子、载重和乘客数为:汽车的轮子、载重和乘客数为:m_passenger=passenger;m_passenger=passenger;CarInstance.GetWheels()tCarInstance.GetWeight()t; CarInstance.GetWheels()tCarInstance.GetWeight()t; coutCarInstance.GetPassenger()endl; coutCarInstance.GetPassenger()endl; /调调用用派派生生类类新新增增的的函函数数GetPassengerGetPassenger 71课堂优质程序运行结果为:程序运行结果为:交通工具轮子的个数是:交通工具轮子的个数是:4 4交通工具轮子的载重为:交通工具轮子的载重为:6 6汽车的轮子、载重和乘客数为:汽车的轮子、载重和乘客数为:1 2 41 2 472课堂优质3.5 类的多态性类的多态性 3.5.1 3.5.1 多态性概述多态性概述3.5.2 3.5.2 多态性的类型多态性的类型 3.5.3 3.5.3 编译时多态性的两种方式编译时多态性的两种方式3.5.4 3.5.4 运行时多态性的实现条件运行时多态性的实现条件3.5.5 3.5.5 纯虚函数与抽象类纯虚函数与抽象类 3.5.6 3.5.6 * * 使用虚函数的好处使用虚函数的好处习题习题73课堂优质3.5.1 多态性概述多态性概述 在在VC中中,这这种种同同一一符符号号或或名名字字在在不不同同情情况况下下表表现为不同的语义现象称为现为不同的语义现象称为多态性。多态性。 严严格格地地讲讲,在在VC中中,不不同同的的类类可可以以有有语语义义相相同同的的函函数数,这这些些函函数数在在概概念念上上是是相相似似的的,但但对对应应各各自自的的类类来来说说,其其实实现现是是不不同同的的,因因而而对对象象在在接接收收到到同同样样的的函函数数调调用用时时所所引引发发的的行行为为有有可可能能是是不不同同的的,这这一一功功能能称称为为多多态态性性。直直观观地地讲讲就就是是“一一个个名名称称,多多个函数个函数”。74课堂优质3.5.2 多态性的类型多态性的类型 程序设计的多态性有两种形式:程序设计的多态性有两种形式:编译时编译时的多态性的多态性和和运行时运行时的多态性。的多态性。 多多态态性性的的实实现现与与联联编编有有关关。将将一一个个函函数数的的调调用用与与其其相相应应的的函函数数体体代代码码相相链链接接的的过过程程,称称为为函函数数联联编编。C+中中有有两两种种类类型型的的联联编编:静静态态联联编编和和动动态态联联编。编。75课堂优质 静静态态联联编编是是指指在在调调用用同同名名函函数数(即即重重载载函函数数)时时,编编译译器器将将根根据据调调用用时时所所使使用用的的实实际际参参数数个个数数、类类型型的的不不同同确确定定应应该该调调用用哪哪一一个个函函数数的的实实现现,它它是是在在程程序序编编译译阶阶段段就就确确定定下下来来的的多多态态性性。静静态态联联编编通通过过使使用用重重载载(overload)机机制制来来获获得得,重重载载机机制制包包括括函数重载和运算符重载。函数重载和运算符重载。 动态联编动态联编是在程序的运行阶段根据当时的情况是在程序的运行阶段根据当时的情况来确定应该调用哪个同名函数的实现。动态联编主来确定应该调用哪个同名函数的实现。动态联编主要通过继承与虚函数两者结合来实现的。要通过继承与虚函数两者结合来实现的。 76课堂优质 静静态态联联编编的的代代码码链链接接工工作作是是在在编编译译时时完完成成的的,所所以以运运行行时时不不需需要要额额外外时时间间来来做做这这些些工工作作,因因此此静静态态联联编的代码编的代码效率较高效率较高。 动动态态联联编编将将函函数数调调用用的的链链接接时时间间后后移移到到代代码码执执行行的的时时候候,这这必必然然使使函函数数调调用用时时间间开开销销增增加加,效效率率降降低低,但但大大大大增增强强了了语语言言的的灵灵活活性性。程程序序员员可可以以根根据据实实际际情情况况需需要要来来决决定定使使用用哪哪一一种种联联编编方方式式,从从而而兼兼顾顾代代码码的的高效性和灵活性。高效性和灵活性。 静态联编与动态联编各有优缺点静态联编与动态联编各有优缺点:77课堂优质3.5.3 编译时多态性的两种编译时多态性的两种形式形式-函数与运算符重载函数与运算符重载1函数重载函数重载 两两个个以以上上的的函函数数,取取相相同同的的函函数数名名称称,但但是是形形参参个个数数或或者者类类型型不不同同,编编译译器器根根据据实实参参和和形形参参的的类类型型和和个个数数选选择择最最匹匹配配的的函函数数,来来自自动动地地确确定定调调用用哪哪一一个个函函数数,这这就就是是函函数数的的重重载载。函函数数重重载载包包括括普普通通成成员员函函数数重重载载和和类类的成员函数重载的成员函数重载 ,下面给出相应的实例。,下面给出相应的实例。 【例例3-20】 普普通通函函数数重重载载的的例例子子。给给函函数数add()定定义义多多个个函函数数来来实实现现,该该函函数数的的功功能能是是求求和和,可可以以求求两两个个整整型型数数之之和和,两两个个浮浮点点数数之之和和,也也可可以以求求三三个个双双精精度度浮浮点点数数之之和和,每每种种实实现现对对应应着着一一个个函函数数体体,这这些些函函数数的的名名字字相相同同,但但是是函函数数的的参参数数个个数数或或类类型型不不同同,这这就就是是函函数数重重载载。在在VC+中中,函函数数可可以以共共享享同同一一个个名名字字,只只是是这这些些同同名名函函数数的的参参数数表表有有所所不不同同。程程序序的的主主文文件为件为Function.cpp。78课堂优质#includeint add(int a,int b)return a+b; float add(float x, float y)return x+y; void add(double a,double b,double c)couta+b+cendl; void main() int m=1,n=2; float x=1.2,y=2.3; double a=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函数函数79课堂优质 从从 程程 序序 的的 运运 行行 结结 果果 来来 看看 add(m,n)是是 调调 用用 了了 int add(int a,int b)函数;函数;add(x,y)调用了函数调用了函数float add(float x, float y);add(a,b,c)调调用用了了void add(double a,double b,double c)函函数数。这这些些函函数数可可以同名,同名的函数为重载函数。以同名,同名的函数为重载函数。程序的运行结果是:程序的运行结果是:33.57.580课堂优质 注意:注意:(1)函数重载时,函数声明必须能函数重载时,函数声明必须能互相区别,即互相区别,即函数参数个数或参数类型必须有函数参数个数或参数类型必须有所不同所不同,如果只有函数的返回值不同,不能区,如果只有函数的返回值不同,不能区分重载函数;(分重载函数;(2)函数功能一般相类似,本)函数功能一般相类似,本质上有区别的函数,最好不要重载;(质上有区别的函数,最好不要重载;(3)不)不同参数传递方式无法区别重载函数。例如:同参数传递方式无法区别重载函数。例如:intadd(inta,intb);intadd(int&a,int&b);这两这两个函数不能作为重载函数,编译时会出错。个函数不能作为重载函数,编译时会出错。 81课堂优质【例【例3-21】类的成员函数重载的例子。】类的成员函数重载的例子。 类类的的成成员员函函数数重重载载的的最最典典型型的的情情况况在在类类的的构构造造函函数数的的重重载载。MFC类类库库中中有有一一个个点点类类CPoint,查查看看MSDN的的说说明明,知知道道它它有有多多个个构构造造函函数数,下下面面为其中的构造函数的原型说明:为其中的构造函数的原型说明:CPoint( int initX, int initY );CPoint( int initX, int initY );CPoint( POINT initPt );CPoint( POINT initPt );CPoint( SIZE initSize );CPoint( SIZE initSize );82课堂优质2运算符重载运算符重载 运算符重载本质上就是函数的重载,是函数重运算符重载本质上就是函数的重载,是函数重载的特殊形式(函数名为运算符号),载的特殊形式(函数名为运算符号),VC语言中允语言中允许程序员重新定义运算符的语义,这一机制称为运许程序员重新定义运算符的语义,这一机制称为运算符重载。算符重载。 与与函函数数重重载载类类似似,运运算算符符重重载载就就是是当当运运算算符符的的操操作作对对象象不不同同时时,运运算算符符呈呈现现出出不不同同的的运运算算状状态态。运运算算符符函函数数有有两两种种形形式式:一一种种是是在在类类中中定定义义的的运运算算符符成成员员函函数数,即即类类成成员员运运算算符符;另另一一种种是是在在类类之之外外定定义义的的运运算算符符函函数数,通常使用友元形式,即友元运算符通常使用友元形式,即友元运算符 。83课堂优质类的运算符重载的定义形式类的运算符重载的定义形式类型类型 类名类名:operatoroperator重载运算符(参数表)重载运算符(参数表) /运算符函数体运算符函数体 【例【例3-223-22】用类的成员函数重载运算符】用类的成员函数重载运算符“+ +”实现复数实现复数相加的例子,重载运算符相加的例子,重载运算符“= = =”实现两个复数是否相实现两个复数是否相等的判断。程序的主文件为等的判断。程序的主文件为Operator.cppOperator.cpp84课堂优质#include iostream.hclass TComplex /定义数学上的复数类定义数学上的复数类public:TComplex(float real=0,float image=0); /缺省构造函数缺省构造函数TComplex(const TComplex &other); /拷贝构造函数拷贝构造函数TComplex operator +(const TComplex &other); /加法运算符重载加法运算符重载bool operator =(const TComplex &other) /判断两个复数是否相等的内联函数实现判断两个复数是否相等的内联函数实现return (m_real=other.m_real)&(m_image=other.m_image); void ShowValue(); /显示复数值显示复数值private:float m_real; /复数的实部复数的实部float m_image;/复数的虚部复数的虚部;85课堂优质TComplex:TComplex(float real,float image) /缺省的构造函数的实现缺省的构造函数的实现m_real=real;m_image=image;TComplex:TComplex(const TComplex &other) /拷贝构造函数的实现拷贝构造函数的实现m_real=other.m_real;m_image=other.m_image;TComplex TComplex:operator +(const TComplex &other) /加法运算符重载的实现代码加法运算符重载的实现代码TComplex temp;temp.m_real=m_real+other.m_real;temp.m_image=m_image+other.m_image;return temp;86课堂优质void TComplex:ShowValue() /显示复数值代码显示复数值代码 cout0)cout+m_imagei; if(m_image0)coutm_imagei; coutendl;void main()TComplex Complex1(6,8); /将复数将复数Complex1设置为设置为4+5iTComplex Complex2(-2,-3); /将复数将复数Complex1设置为设置为-2-3i,调用缺省构造函数完成调用缺省构造函数完成TComplex Complex3(Complex1); /用用Complex1初始化初始化Complex3,调用拷贝构造函数完成后,这两个调用拷贝构造函数完成后,这两个复数相等复数相等TComplex Complex4,Complex5; /将复数将复数Complex4,Complex5设置为设置为0,调用缺省构造函数完成调用缺省构造函数完成87课堂优质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;88课堂优质程序运行结果:程序运行结果:6+8i-2-3i6+8i004+5i4+5iComplex4和和Complex5相相等等 运算符重载增加了程序的灵活性,但运算符重载不运算符重载增加了程序的灵活性,但运算符重载不能改变运算符的基本功能,也不能改变运算符的优先级能改变运算符的基本功能,也不能改变运算符的优先级和结合性,运算符重载不能使用缺省参数。和结合性,运算符重载不能使用缺省参数。89课堂优质3.5.4 运行时多态性运行时多态性的实现条件的实现条件1定定义义超超载载(overriding)函函数数要要使使程程序序出出现现运运行行时时的的多多态态性性,必必须须有有继继承承关关系系。在在类类的的层层次次结结构构中中,定定义义完完全全相相同同的的函函数数原原型型,但但这这些些类类层层次次中中同同名名函函数数的的实实现现代代码码却却不不同同。这这些些不不仅仅同同名名而而且且同同原原型型的的函函数数称作函数的超载(称作函数的超载(overrideoverride)。)。 2声明超声明超载载函数函数为为虚函数虚函数 1 1、声明虚拟函数、声明虚拟函数 class TAnimalclass TAnimal private: private: char m_strName10;char m_strName10; public: public: virtual void Roar() virtual void Roar() coutcout并并不不知知道道哪哪个个类类的的动动物物在在叫叫endl;/endl;/此此函函数数说说明明为为虚虚函函数数 ; 2 2 、使用继承、使用继承 90课堂优质3通通过过基基类类指指针针来来访问访问 一般情况下,指向一种类型对象的指针不允许指向另一种一般情况下,指向一种类型对象的指针不允许指向另一种类型的对象。但类型的对象。但指向基类的指针可以指向派生类对象指向基类的指针可以指向派生类对象 【例【例3-233-23】虚函数和多态性的应用实例。】虚函数和多态性的应用实例。 程程序序中中定定义义了了鸟鸟类类、狗狗类类和和老老虎虎类类,我我们们知知道道,不不论论是是鸟鸟、狗狗还还是是老老虎虎,他他们们都都会会叫叫,但但它它们们的的叫叫声声是是完完全全不不同同的的。如如果果这这三三个个类类都都有有一一个个叫叫Roar()Roar()的的成成员员函函数数,那那么么在在这这三三个个类类的的RoarRoar函函数数的的实实现现代代码码肯肯定定是是不不一一样样的的。在在TAnimalTAnimal类类的的RoarRoar函函数数之之前前加加上上VirtualVirtual,使使其其成成为为虚虚函函数数,然然后后再再通通过过指指向向基基类类TAnimalTAnimal的的指指针针来来访访问问,就就可可实实现现运运行行时时的的多多态态性性。程序的主文件为程序的主文件为DynaPoly.cppDynaPoly.cpp。91课堂优质# #include include #include #include #include #include class TAnimalclass TAnimal private:private:char m_strName10;char m_strName10;public:public:virtual void Roar()virtual void Roar()coutcout并不知道哪个类的动物在叫并不知道哪个类的动物在叫endl;endl;void SetName(char *strName)void SetName(char *strName)strcpy(m_strName,strName);strcpy(m_strName,strName); char *GetName()char *GetName() return m_strName;return m_strName; ; class TBird:public TAnimal /; class TBird:public TAnimal /定义鸟类定义鸟类TBirdTBird public:public:TBird() SetName(Bird);TBird() SetName(Bird);void Roar()void Roar()coutTheGetName()is coutTheGetName()is RoaringRoaringis is it it a a good good singer?n;singer?n; ;92课堂优质class TDog:public TAnimal /class TDog:public TAnimal /定义狗类定义狗类TDogTDog public:public:TDog() SetName(Dog);TDog() SetName(Dog);void Roar()void Roar()coutThe GetName()is RoaringcoutThe GetName()is Roaringis it boring?n;is it boring?n; ;class TTiger:public TAnimal /class TTiger:public TAnimal /定义老虎类定义老虎类TTigerTTiger public:public:TTiger() SetName(Tiger);TTiger() SetName(Tiger);void Roar()void Roar()coutTheGetName()coutTheGetName()“is Roaringis Roaringis it frightful?n;is it frightful?n; ;93课堂优质void main()void main() TAnimal animal;TAnimal animal; TBird bird;TBird bird;TDog dog;TDog dog;TTiger tiger;TTiger tiger; cout cout以下为静态联编以下为静态联编-n;n;/通过对象的方式来访问是静态联编通过对象的方式来访问是静态联编animal.Roar();animal.Roar();bird.Roar();bird.Roar();dog.Roar();dog.Roar();tiger.Roar();tiger.Roar();coutcoutRoar();pAnimal-Roar();pAnimal=&dog;pAnimal=&dog;pAnimal-Roar();pAnimal-Roar();pAnimal=&tiger;pAnimal=&tiger;pAnimal-Roar();pAnimal-Roar(); 94课堂优质 程序运行结果为:程序运行结果为: 以下为静态联编以下为静态联编- 并不知道哪个类的动物在叫并不知道哪个类的动物在叫 The Bird is Roaring.is it a good singer? The Bird is Roaring.is it a good singer? The Dog is Roaring.is it boring? The Dog is Roaring.is it boring? The Tiger is Roaring.is it frightful? The Tiger is Roaring.is it frightful? 以下为动态联编以下为动态联编- The Bird is Roaring.is it a good singer? The Bird is Roaring.is it a good singer? The Dog is Roaring.is it boring? The Dog is Roaring.is it boring? The Tiger is Roaring.is it frightful? The Tiger is Roaring.is it frightful?95课堂优质 通通过过指指针针的的方方式式来来访访问问虚虚函函数数是是动动态态联联编编,倘倘若若把把派派生生类类的的Roar函函数数前前的的virtual去去掉掉,则则变变为为静静态态联联编编。自自己把去掉己把去掉virtual的程序运行一下,其运行结果为:的程序运行一下,其运行结果为:以下为静态联编以下为静态联编-并不知道哪个类的动物在叫并不知道哪个类的动物在叫The Bird is Roaring.is it a good singer?The Bird is Roaring.is it a good singer?The Dog is Roaring.is it boring?The Dog is Roaring.is it boring?The Tiger is Roaring.is it frightful?The Tiger is Roaring.is it frightful?96课堂优质以下为动态联编以下为动态联编-并不知道哪个类的动物在叫并不知道哪个类的动物在叫并不知道哪个类的动物在叫并不知道哪个类的动物在叫并不知道哪个类的动物在叫并不知道哪个类的动物在叫 可可见见要要实实现现动动态态联联编编,必必须须将将基基类类的的Roar定定义义成成为为虚虚函数,这种情形称为函数的函数,这种情形称为函数的超载(超载(Override)或同名覆盖或同名覆盖97课堂优质3.5.5 纯虚函数与抽象类纯虚函数与抽象类(1)(1)纯虚函数的定义纯虚函数的定义 在基类中只声明虚函数而不给出具体的定义,将它的在基类中只声明虚函数而不给出具体的定义,将它的具体定义放在各派生类中,称此虚函数为纯虚函数(具体定义放在各派生类中,称此虚函数为纯虚函数(pure pure virtual functionvirtual function)。)。 声明了纯虚函数的类,称为抽象类(声明了纯虚函数的类,称为抽象类(abstract classabstract class)。)。纯虚拟函数的声明形式如下:纯虚拟函数的声明形式如下:virtual virtual 函数类型函数类型 函数原型(参数表)函数原型(参数表)=0=0;将虚拟函数的原型设置为将虚拟函数的原型设置为0 0,该,该虚函数即为纯虚函数。虚函数即为纯虚函数。98课堂优质(2 2)抽象类的定义)抽象类的定义 只能用作别的类的基类,而本身不能直接创建对象的只能用作别的类的基类,而本身不能直接创建对象的类称为抽象基类。类称为抽象基类。带有纯虚函数的基类是抽象类。带有纯虚函数的基类是抽象类。 抽抽象象类类派派生生一一个个新新类类后后,可可以以对对虚虚函函数数添添加加实实现现代代码码,此时,该类就不再是抽象类;反之仍然为抽象类。此时,该类就不再是抽象类;反之仍然为抽象类。(3 3)抽象类的使用)抽象类的使用 【例例3-24】纯纯虚虚函函数数的的例例子子。下下面面的的程程序序用用于于计计算算三三角角形形和和矩矩形形的的面面积积,设设计计一一个个抽抽象象类类shapeshape,它它表表示示具具有有形形状状的的东东西西,体体现现了了抽抽象象的的概概念念,在在它它下下面面可可以以派派生生出出多多种种具具体体形形状状,比比如如三三角角形形、矩矩形形、椭椭圆圆等等。为为了了计计算算这这些些图图形形的的面面积积,只只需需在在类类shapeshape中中声声明明一一纯纯虚虚函函数数area()area(),而而将将计计算算具具体体形形状状面面积积的的定定义义放放到到其其派生类中。程序的主文件为派生类中。程序的主文件为VirtualFunc.cppVirtualFunc.cpp。99课堂优质 # #include include class shape class shape protected: protected: double x, y; double x, y;public:public: void set (double i, doube j)x=i; y=j; void set (double i, doube j)x=i; y=j; virtual void area()=0;/ virtual void area()=0;/声明纯虚函数声明纯虚函数 ;/抽象类抽象类shaptshapt定义结束定义结束class triangle: public shapeclass triangle: public shape public: public: void area() void area() cout cout ” Triangle S=1/2* Triangle S=1/2*” x x”* *” y y”= =”0.5*x*y0.5*x*y”nn”; ; / / 派生类重新定义虚拟函数派生类重新定义虚拟函数 ;100课堂优质class rectangle: public shapeclass rectangle: public shape public: public: void area( ) void area( ) cout cout ” Rectangle S= Rectangle S=” x x”* *” y y ”= =”x*yx*yset(5.1,10); p-set(5.1,10); p- area( ); p- area( ); p=&r; p=&r; p-set(5.1,10); p-set(5.1,10); p-area(); p-area(); 101课堂优质程序输出结果是:程序输出结果是:Triangle S=1/2*5.1*10.0=25.5Triangle S=1/2*5.1*10.0=25.5Rectangle S=5.1*10.0=51.0Rectangle S=5.1*10.0=51.0 基基类类shape shape 只只为为派派生生类类提提供供一一个个接接口口area(),area(),在在派派生生类类中中给给出出area()area()的的具具体体定定义义,因因此此将将函函数数area()area()声声明明为为纯纯虚虚函函数数。当当shapeshape的的指指针针p p指指向向派派生生类类triangletriangle的的对对象象t t时时,语语句句p p - - area( area( ) )调调用用triangletriangle类类的的函函数数area( area( ),),显显示示三三角角形形的的面面积积。当当p p指指向向rectanglerectangle类类的的对对象象r r时时,相相同同语语句句p-area()p-area()调调用用的的是是rectanglerectangle类类的的函函数数area(),area(),显显示矩形的面积。示矩形的面积。 注注意意:从从抽抽象象类类可可以以派派生生出出具具体体或或抽抽象象类类,但但不不能能从从具体类派生出一个抽象类。具体类派生出一个抽象类。102课堂优质(1)可以使程序简单易懂;)可以使程序简单易懂;(2)使程序模块间的独立性加强,增加了程序的易维护性;)使程序模块间的独立性加强,增加了程序的易维护性;(3)提高了程序中)提高了程序中“信息隐藏信息隐藏”的等级;的等级;(4)提高了)提高了“软件重用软件重用”的等级。的等级。虚函数虚函数是一类簇对外提供的是一类簇对外提供的接口接口,它实质上是一种接口重用。,它实质上是一种接口重用。3.5.6 * 使用虚函数的好处使用虚函数的好处 在在程程序序设设计计中中利利用用虚虚函函数数实实现现类类的的成成员员函函数数的的动动态态联联编编,可可以以提提高高程程序序的的质质量量,采采用用虚虚函函数数对对程程序序的的好处有:好处有:103课堂优质 习习 题题一、单选题:一、单选题: 1 1下列说法正确的是下列说法正确的是_ A.A.内内联联函函数数在在运运行行时时是是将将给给函函数数的的目目标标代代码码插插入入每每个个调调用该函数的地方用该函数的地方B.内内联联函函数数在在编编译译时时是是将将给给函函数数的的目目标标代代码码插插入入每每个个调调用该函数的地方用该函数的地方 C.类的内联函数必须在类体内定义类的内联函数必须在类体内定义 D.类的内联函数必须在类体外通过关键字类的内联函数必须在类体外通过关键字inline inline 定义定义 2为同一函数和运算符定义几个版本是为同一函数和运算符定义几个版本是VCVC语言的语言的_ A. A. 抽象性抽象性 B. B. 继承性继承性 C. C. 灵活性灵活性 D. D. 多态性多态性104课堂优质 3.3.下列关于封装的说法中正确的是下列关于封装的说法中正确的是_ A. A. 在在VCVC中,封装是借助于函数达到的中,封装是借助于函数达到的 B.封装不要求对象具有明确的功能封装不要求对象具有明确的功能C.在数据封装的情况下,用户可以直接操作数据在数据封装的情况下,用户可以直接操作数据D.封封装装是是将将一一组组数数据据和和与与这这组组数数据据有有关关的的集集合合组组装在一起,形成一个能的实体装在一起,形成一个能的实体 4. 4.动态联编所支持的多态性称为动态联编所支持的多态性称为_ A.虚函数虚函数 B. B. 继承继承 C.C.编译时多态性编译时多态性 D. D. 运行时多态性运行时多态性105课堂优质二、简答题:二、简答题: 1什么叫多态性?在什么叫多态性?在C+C+中是如何实现多态性的?中是如何实现多态性的? 2 2虚函数与多态性有什么关系?虚函数与多态性有什么关系? 3 3构造函数和析构函数各有什么作用?构造函数和析构函数各有什么作用? 4 4虚虚函函数数的的超超载载又又叫叫函函数数的的同同名名覆覆盖盖,结结合合实实例例谈谈谈谈什什么么叫叫同名覆盖同名覆盖? ? 5 5类类有有哪哪几几类类继继承承方方式式?以以ProtectedProtected继继承承方方式式派派生生的的类类对对基类的继承性如何?基类的继承性如何? 6 6什么叫抽象类?它有哪些作用?什么叫抽象类?它有哪些作用?106课堂优质三、程序分析三、程序分析 下下面面的的类类是是从从MFC的的源源代代码码afx.h中中提提取取出出来来的的有有关关CString类的定义,利用本章所学的知识,看能否阅读懂。类的定义,利用本章所学的知识,看能否阅读懂。class CStringclass CString public:public:/ Constructors/ Constructors/ constructs empty CString/ constructs empty CStringCString();CString();/ copy constructor/ copy constructorCString(const CString& stringSrc);CString(const CString& stringSrc);/ from a single character/ from a single character/ Attributes & Operations/ Attributes & Operations/ get data length/ get data lengthint GetLength() const;int GetLength() const;/ TRUE if zero length/ TRUE if zero lengthBOOL IsEmpty() const;BOOL IsEmpty() const; / clear contents to empty/ clear contents to empty107课堂优质 MakeUpper();MakeUpper(); void MakeLower(); void MakeLower(); void TrimLeft(); void TrimLeft(); void TrimLeft(TCHAR chTarget); void TrimLeft(TCHAR chTarget);public:public:CString();CString();int GetAllocLength() const;int GetAllocLength() const;protected:protected:LPTSTR LPTSTR m_pchData; m_pchData; / / pointer pointer to to ref ref counted counted string datastring data/ implementation helpers/ implementation helpersCStringData* GetData() const;CStringData* GetData() const;108课堂优质void Init();void Init();void void llocCopy(CString&dest,int llocCopy(CString&dest,int nCopyLen,int nCopyLen,int nCopyIndex, int nExtraLen) const;nCopyIndex, int nExtraLen) const;void AllocBuffer(int nLen);void AllocBuffer(int nLen);void AssignCopy(int nSrcLen, LPCTSTR lpszSrcData);void AssignCopy(int nSrcLen, LPCTSTR lpszSrcData);void void ConcatInPlace(int ConcatInPlace(int nSrcLen, nSrcLen, LPCTSTR LPCTSTR lpszSrcData);lpszSrcData);void CopyBeforeWrite();void CopyBeforeWrite();void Release();void Release();static void PASCAL Release(CStringData* pData);static void PASCAL Release(CStringData* pData);bool bool AFXAPI AFXAPI operator=(const operator=(const CString& CString& s1, s1, const const CString& CString& s2);s2);bool AFXAPI operator=(LPCTSTR s1, const CString& s2);bool AFXAPI operator=(LPCTSTR s1, const CString& s2); 109课堂优质四、编程题:四、编程题: 1声声明明一一个个点点类类TPoint,并并对对其其运运算算符符号号“+”与与“-” 进行重载。进行重载。 2声声明明一一个个水水果果类类,并并描描述述它它们们的的一一些些特特性性,且且由由此此派派生生出出香香蕉蕉类类和和荔荔枝枝类类,并并编编写写成成员员函函数数描描述述它它的的一一些基本功能。些基本功能。110课堂优质
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号