




已阅读5页,还剩98页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
VisualC+面向对象编程语言,第三章C+面向对象程序设计,第三章C+面向对象程序设计,3.1面向对象程序设计概述,3.1.1传统的结构化程序设计3.1.2面向对象程序设计方法及特征,3.2C+类,3.2.1类的定义与实现3.2.2构造函数和析构函数3.2.3this指针3.2.4静态成员3.2.5友元,3.3类的继承,3.3.1基类和派生类3.3.2基类和派生类的构造函数3.3.3多重继承3.3.4虚基类,3.4多态性和虚函数,3.4.1用基类指针指向派生类对象3.4.2虚函数3.4.3抽象类和纯虚函数,3.5重载,3.5.1函数重载3.5.2运算符重载,3.6C+模板,3.6.1函数模板3.6.2类模板,3.7MicrosoftVisualC+的语法扩充,3.7.1VisualC+自定义数据类型3.7.2VisualC+运行库3.7.3运行时类型识别3.7.4编程规范,结构化程序设计:将系统分解为若干模块(即函数);缺点:维护困难,特别是数据结构的修改;,3.1.1传统的结构化程序设计,3.1.2面向对象程序设计方法及特征,对象数据作用于这些数据上的操作;类是具有相同数据结构和相同操作功能的对象的集合,对象是类的实例;对象与类的关系类似于鞋和生产鞋的模具;,面向对象程序设计把一个复杂的问题分解为多个能完成独立功能的对象,分开独立设计,再将其整合完成复杂问题;其理想目标是希望编写程序就像搭积木;,面向过程和面向对象的区别,面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。,例如五子棋,面向过程的设计思路就是首先分析问题的步骤:1、开始游戏,2、黑子先走,3、绘制画面,4、判断输赢,5、轮到白子,6、绘制画面,7、判断输赢,8、返回步骤2,9、输出最后结果。把上面每个步骤用分别的函数来实现,问题就解决了。,而面向对象的设计则是从另外的思路来解决问题。整个五子棋可以分为:1、黑白双方,这两方的行为是一模一样的,2、棋盘系统,负责绘制画面,3、规则系统,负责判定诸如犯规、输赢等。第一类对象(玩家对象)负责接受用户输入,并告知第二类对象(棋盘对象)棋子布局的变化,棋盘对象接收到了棋子的变化就要负责在屏幕上面显示出这种变化,同时利用第三类对象(规则系统)来对棋局进行判定。,可以明显地看出,面向对象是以功能来划分问题,而不是步骤。同样是绘制棋局,这样的行为在面向过程的设计中分散在了总多步骤中,很可能出现不同的绘制版本,因为通常设计人员会考虑到实际情况进行各种各样的简化。而面向对象的设计中,绘图只可能在棋盘对象中出现,从而保证了绘图的统一。,功能上的统一保证了面向对象设计的可扩展性。比如我要加入悔棋的功能,如果要改动面向过程的设计,那么从输入到判断到显示这一连串的步骤都要改动,甚至步骤之间的循序都要进行大规模调整。如果是面向对象的话,只用改动棋盘对象就行了,棋盘系统保存了黑白双方的棋谱,简单回溯就可以了,而显示和规则判断则不用顾及,同时整个对对象功能的调用顺序都没有变化,改动只是局部的。,在类的定义中,数据称为成员变量,函数称为方法;成员变量按访问控制权限分为公有和私有;定义的格式:classprivate:public:protected:,3.2.1类的定义与实现,private属性的成员只允许被本类的成员函数访问和调用;protected属性的成员允许被本类的成员函数和派生类的成员函数访问和调用;,例:Time类的定义classTimeprivate:inthour;intminute;intsecond;public:voidsetTime(int,int,int);voidshowTime();,为什么需要这两个函数?,对于成员函数来讲,成员变量就像全局变量;,类的定义和一般函数定义类似,但必须在成员函数名前加类名和作用域限定符(:)Time类的实现(定义)voidTime:setTime(inth,intm,ints)hour=(h=0,对象的声明:就像变量的声明(用模具生产一个产品);格式:;例:Timet1,today;Time*pt1=,在面向对象程序设计中,程序设计范型变成了:确定你需要哪些类型,为每个类型提供完整的一组操作。,思考:如果对于Time类,在未调用setTime前调用showTime会怎样?,我们需要对成员变量初始化;构造函数是一种特殊的成员函数,函数名和类名相同,提供了对成员变量初始化的方法,使得声明对象时自动初始化对象,当声明对象时,自动调用构造函数;析构函数也是成员函数,用来在系统释放对象前做一些清理工作,当对象注销时,自动调用析构函数;,3.2.2构造函数和析构函数,构造函数的名称与类名相同,而析构函数必须在类名前加“”,都没有返回值;构造函数可以有参数,析构函数没有参数;系统有默认的构造函数和析构函数;可以有多个构造函数(参数类型不同),使得创建的对象根据数据类型的不同(整型和实型)进行不同的处理,这就是函数重载;,public:Time(int,int,int);Time();Time:Time(inth,intm,ints)hour=h;minute=m;second=s;Time:Time(),例Voidmain(void)Timet1(10,20,30);/调用构造函数/调用析构函数,理解面向对象设计的思想,例:计算一个矩形的面积和周长,计算一个矩形的面积和周长,从面向过程的角度出发思考这个问题;先确定面积和周长的算法(这个很简单,小学知识)编写2个方法分别计算面积和周长,在一个类里面考虑到计算周长和面积需要至少2个参数,长和宽;程序如下:,intperimeter(intlength,intwidth)return2*(length+width);intarea(intlength,intwidth)returnlength*width;,voidmain()coutperimeter(4,5);cout“n”coutarea(4,5);,下面再从面向对象的角度出发,重新考虑这个问题:一个长方形可以看成一个长方形对象。既然是对象,那么它就有属性(长和宽)和行为(周长和面积)抽取长方形的共性,设计一个类通过对象的行为,就可以求出某个具体的长方形对象的周长和面积,classRectangle()public:intlength,width;intperimeter()return2*(length+width);intarea()returnlength*width;,voidmain()Rectanglerect1=newRectangle();rect1.length=10;rect1.width=5;coutrect1.perimeter();coutrect1.area();,在C方案中扩展困难,原因就在于没有一个合适的位置来存储辅助的状态信息,因为在原来的情况下根本不需要状态信息;对象提供了一个理想的位置来放置状态信息,并且作为对象的一部分是显示可用的,而不是隐藏在幕后的东西;,继续思考面向对象的特点,在面向过程的思想里,一个程序一般都是由一个个函数组成的,这些函数之间相互调用,就形成了一个完整的程序,解决了一个问题。它的基本结构是:,函数一();函数二();主函数();,在面向对象的思想中,是把这些都封装起来,形成一个类。,class类名函数一();函数二();,然后由这个类产生一个对象,比如:我们把一个类的类名起为student那么产生对象的方法就是:students1;这里s1是一个对象,产生了这个对象以后,才可以进行相关操作。操作方法如:s1.函数一();,假设我们要做一个小游戏,类似于网游里面的打怪,为简单起见,认为怪不打人,只让人打,他的血不断减少,直到死亡。,把所有怪物的共同特征抽象出来,于是我们得到一个类:怪物class怪物char怪物名;int血;,怪物:怪物(怪物名n,血n)/*构造函数*/怪物名=怪物名n;血=血n;,怪物:被打函数()血减少;怪物:判断函数()if(血=0)cout0)被打函数();判断函数();,main主函数voidmain()/*产生对象*/怪物怪物1(狼,5000);怪物怪物2(虎,8000);怪物怪物3(蛇,3000);,怪物1.玩游戏();怪物2.玩游戏();怪物3.玩游戏();,指向对象本身的指针,作为隐含参数传给每个成员函数;例:voidTime:showTime()couthourminute,3.2.3this指针,Time:showTimeDisplay(this);,Display(Time*pObj),This指针对于在非本类成员函数中使用对象成员变量,需要让多个对象共享相同值的成员时使用;成员变量定义:staticintm_ncount;使用和一般成员变量一样,也有公有、私有之分;初始化必须在类定义的外部:intPerson:m_nCount=0;,3.2.4静态成员,成员函数也可以是静态的;定义staticintGetCount();没有this指针;可以通过类调用:Person:GetCount();也可以通过对象调用:e1.GetCount();静态成员函数只能访问类的静态成员;如需访问非静态成员,需将对象作为参数传入;longPerson:GetID(Personx);,3.2.5友元,友元函数:访问其他类的私有成员变量的函数;一个类可以声明一个函数为其友元函数;作用:编程方便;定义:classAfriendvoiddisplay(A);private:inta;,voiddisplay(Ae)coute.avoidmain()display(a1);,classBpublic:voidfun1(A,一个类的成员函数作为另一个类的友元函数,voidmain()Aa1;Bb1;b1.fun1(a1);,友元类:类A可以声明类B为其友元类,类B的所有成员函数都可以访问A的所有成员;定义classCpublic:voidfun2(A,voidC:fun2(A,classBpublic:voidfun1(A,voidB:fun1(Ae)e.a=10;voidmain()Aa1;Bb1;b1.fun1(a1);,classBpublic:voidfun1(A),classBpublic:voidfun1(A,a1.a,e.a,voidB:fun1(Ae)e.a=10;voidmain()Aa1;Bb1;b1.fun1(a1);,classBpublic:voidfun1(A),a1.a,e.a,3.3类的继承,实现代码重用和扩充;拷贝代码受到版权的各方面因素影响;,3.3.1基类和派生类,在继承关系中,新定义的类称为被继承类的派生类或子类,被继承的类称为新定义类的基类或父类;格式:class:;派生方式:public、private和protected(默认为private);,无论何种派生方式,基类的私有成员都不能在派生类中使用;例classAprivate:inta;public:intGeta()returna;,classB:publicAvoidmain()Bb1;b1.Geta();b1.a:=3;,classBprivate:inta;public:intGeta()returna;,思考:如果不采用继承定义B类?,classB:publicA,public派生:基类成员访问权限不变,可以通过派生类对象访问基类公有成员;private派生:基类所有成员成为私有成员,只能通过派生类的成员函数访问基类非私有成员;protected派生:和private差不多;,例classAprivate:inta;public:intGeta()returna;,classB:Avoidmain()Bb1;b1.Geta();/非法,基类中不适合派生类的成员可以在派生类中重新定义,称为覆盖(override);在派生类中定义与基类成员函数名称和参数表相同的函数;例classApublic:voidshow();,classB:publicApublic:voidshow();Bb1;b1.show();,若需要在派生类中调用基类中同名的成员函数,可以使用作用域限定符“:”;,classB:publicApublic:voidshow();voiddisplay()A:show();Bb1;b1.show();b1.display();,3.3.2基类和派生类的构造函数,当程序创建一个派生类对象时,系统首先自动创建一个基类对象,即在调用派生类的构造函数构建派生类对象时,系统首先调用基类的构造函数构建基类对象;当派生类对象的生存期结束时,首先调用派生类的析构对象,然后调用基类的析构函数;派生类中必须显示调用基类的构造函数,除非基类有默认的构造函数;,例:B:B():A()形参时指明派生类构造函数形参的名称和类型,参数表时形参说明中所给出的部分参数,是要传递给基类构造函数的参数;,Point(inta,intb),Circle(inta,intb,intr):Point(a,b),Cylinder(inta,intb,intr,inth):Circle(a,b,r),3.3.3多重继承,单继承:每个派生类只有一个直接基类;多重继承:一个派生类可以同时从多个基类派生而来;格式:class:,;P86例3-11GetAB()returna+b;,3.3.4虚基类,解决二义性问题;每个派生类对象含有基类的数据成员的一个副本,因此派生类对象可能存在间接基类的两份副本。采用虚基类解决;格式(派生类定义)classB:publicvirtualA基类定义不变;,3.4多态性和虚函数,多态性:根据数据不同进行不同的运算处理,如加法,对于实数或整数就是将两数相加,对于复数就是将对应的实部和虚部相加;“一种接口、多种方法”;多态性分为编译时多态性和运行时多态性;编译时多态性又称静态多态性,用来处理函数名相同,但参数类型不同的情况,通过重载机制来实现;运行时多态性:处理函数名、参数和返回值都相同的情况,通过虚函数机制实现;,派生类的对象也可以认为是其基类的对象,但基类的对象不是其派生类的对象;(儿子像老爸)允许基类对象的指针指向其派生类的对象,通过该指针只能访问派生类中从基类继承的公有成员;(老爸的东西也是儿子的东西,老爸只能拿老爸自己的东西)可以通过强制类型转换将基类指针和派生类指针互相转换;,3.4.1用基类指针指向派生类对象,例:classB:publicAvoidsetB()Aa,*pa;Bb,*pb;pa=/通过基类指针访问派生类自定义的成员,pb=/对象a中不存在setB(),3.4.2虚函数,派生类成员函数和基类成员函数具有相同的函数名和参数类型,派生类的成员函数将覆盖基类成员函数;例:classAvoidshow()classB:publicAvoidshow(),Bb;b.show();,若用基类指针指向派生类对象,结果一样;A*pa;Bb;pa=在基类对象中使用虚函数,可以使指向派生类对象的基类指针调用派生类中的覆盖函数(和基类对象成员函数同名);派生类对象的覆盖函数各不相同,但基类对象的虚函数机制,使我们可以通过指向派生类对象的基类指针调用同个函数名,实现不同派生类对象的不同功能,这就是类的多态性;,格式:classApublic:virtualvoidshow();classB:publicApublic:voidshow();voidmain,A*pa;Bb;pa=,利用虚函数机制,我们可以在基类和派生类中使用相同的函数名和参数类型,而定义不同的操作;为同一个类体系中所有派生类的同一类行为提供了统一的接口;,CShape.show,CCircle.show,CSquare.show,CEllipse.show,如果用new运算创建派生类对象;当delete运算撤销派生类对象时,只调用基类的析构函数,没有调用派生类的析构函数;定义基类的析构函数为虚函数可解决问题;格式:classAvirtualA();classB:publicAB();,voidmain()A*pa=newB;deletepa;,开发程序中,常将基类中功能容易变化的成员函数设计成虚函数,然后根据需要设计派生类的虚函数,实现“一种接口、多种方法”;,3.4.3抽象类和纯虚函数,我们可以让基类的一些成员函数没有具体的定义,这种基类只能用于类的继承,其本身不能用来创建对象,这样的类称为抽象类;抽象类只能是基类,它提供了一个框架,仅仅起着统一接口的作用;不能声明抽象类的对象,但可以声明抽象类的指针;抽象类:1、至少有一个成员函数不定义具体实现;2、定义了一个protected访问属性的构造函数或析构函数;,不定义具体实现的成员函数称为纯虚函数;纯虚函数不能调用;格式:virtual()=0;例:classApublic:virtualvoidfun1()=0;,classB:publicApublic:voidfun1();,3.5重载,C+重载分为函数重载和运算符重载;运算可以理解为是调用一个函数;使用重载机制可以对一个函数名(或运算符)定义多个函数(或运算),只不过函数的参数(或运算的数)类型不同;如加法,对于实数或整数就是将两数相加,对于复数就是将对应的实部和虚部相加;,3.5.1函数重载,我们可以通过函数重载机制使一组功能相似但函数参数类型不同的函数共用一个函数名;C+编译器根据参数类型和个数选择正确的函数;P95例3-18求绝对值函数abs()重载;不能利用函数返回类型的不同进行函数的重载;不能利用引用来重载;对于voidfun(int和voidfun(int);fun(i)无法选择调用哪个函数;,利用重载可以设计多个构造函数,为对象提供多种初始化方式;P96例3-19:classBoxpublic:Box();Box(int,int,int);Boxbox1;BoxBox2(10,15,20);,3.5.2运算符重载,运算符重载指对于不同数据类型的操作数,同一个运算符所代表的运算功能可以不同;可以把运算符看成调用运算符函数,如10+20看成int+(10,20);重载运算符就是编写运算符函数;格式operator();,P97例3-20非成员函数重载运算符:classComplexComplexoperator+(Complexc1,Complexc2)voidmain()complex=complex1+complex2;,利用非成员函数重载双目运算符时,运算符函数的第一个参数代表运算符左边的操作数,运算符函数的第二个参数代表运算符右边的操作数;Complexoperator+(Complexc1,Complexc2)如果运算符函数要求访问一个类的非公有成员,则运算符函数不能定义为非成员函数,除非将它声明为该类的友元函数;,P98例3-21成员函数重载运算符:classComplexComplexoperator+(Complex);ComplexComplex:operator+(Complexother)voidmain()complex=complex1+complex2;,利用成员函数重载双目运算符时,运算符左边的操作数就是对象本身,不能再将它作为运算符函数的参数,因此,这时运算符函数只需一个函数参数;Complexoperator+(Complex);,同一个重载运算符的参数个数是相同的;用户不能定义新的运算符,只能对现有的进行重载;重载后的优先级和结合性不变;下列运算符不能重载“.”(成员运算符)“:”(作用域限定符)“?:”(条件运算符)“*”(成员指针选择符);,3.6C+模板,模板:将数据类型参数化的工具;使用模板时根据实参的数据类型确定模板参数的数据类型;避免代码重复编写;,3.6.1函数模板,例:intabs(intval)returnval0?-val:val;floatabs(floatval)returnval0?-val:val;为了避免这种代码的重复编写,C+提供函数模板;,例:template/T是自己定
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 漆器金银漆雕刻嵌银工艺考核试卷及答案
- 磷肥酸沉槽工艺考核试卷及答案
- 微电子制造工艺规范考核试卷及答案
- 金属材碱洗工标准化作业考核试卷及答案
- 电线电缆金属导体挤制工质量管控考核试卷及答案
- 2024新版2025秋青岛版科学六三制三年级上册教学课件:第四单元 第17课 水蒸发
- AI智能智慧教育综合解决方案
- 影像技术防护考试题及答案
- 气象观测业务测试卷附答案
- 银行征信试题及答案
- 重庆.住宅物业单位服务等级标准
- 9第九章-心境障碍PPT
- 全国工会财务知识竞赛题库附答案
- 家族企业女性代际传承问题研究
- 新编商务英语unit市公开课金奖市赛课一等奖课件
- 地图狙击手之中国篇优质课件
- 2023年工具钳工技师(五篇)
- GB/T 42381.61-2023数据质量第61部分:数据质量管理:过程参考模型
- 小儿神经系统查体
- GB 19761-2009通风机能效限定值及能效等级
- 分子泵培训教材课件
评论
0/150
提交评论