c中实现多态的例子

上传人:daj****de2 文档编号:173992977 上传时间:2022-12-13 格式:DOCX 页数:6 大小:29.72KB
返回 下载 相关 举报
c中实现多态的例子_第1页
第1页 / 共6页
c中实现多态的例子_第2页
第2页 / 共6页
c中实现多态的例子_第3页
第3页 / 共6页
点击查看更多>>
资源描述
c中实现多态的例子【篇一:C中实现多态的例子】下面是一个承上启下的例子。一方面它是有关继承和运算符重载内容的综合应用的例子,通过这个例子可以进一步融会贯通前面所学的内容,另一方面又是作为讨论多态性的一个基础用例。希望大家耐心、深入地阅读和消化这个程序,弄清其中的每一个细节。例121先建立一个point点)类,包含数据成员x,y坐标点)。以它为基类,派生出一个circlel)类,增加数据成员r半径),再以circle类为直接基类,派生出一个cylinder圆柱体)类,再增加数据成员h(高)。要求编写程序,重载运算符“和“,”吏之能用于输出以上类对象。这个例题难度不大,但程序很长。对于一个比较大的程序,应当分成若干步骤进行。先声明基类,再声明派生类,逐级进行,分步调试。声明基类point类可写出声明基类point的部分如下:#includeiostream/声明类pointclasspointpublic:pointfloatx=0,floaty=1有默认参数的构造函数voidsetpointfloat,floa设置坐标值floatgetx()constreturnx;读/坐标floatgety()constreturny;/读y坐标friendostreamoperator(ostream,constpoint重载运下面定义point类的成算符“”protected/受保护成员floatx,员函数point:pointfloata,floatb)的构造函数/对x,y初始化x=a;y=b;voidpoint:setpointfloatafloat设置x/和y的坐标值/x,y赋新值x=a;y=b;/重载运算符“,使之能输出点的坐标ostreamoperator(ostreamoutput,constpointp)outputp.x,p.yendl;returnout以上完成了基类point类的声明。为了提高程序调试的效率,提倡对程序分步调试,不要将一个长的程序都写完以后才统一调试,那样在编译时可能会同时出现大量的编译错误,面对一个长的程序,程序人员往往难以迅速准确地找到出错位置。要善于将一个大的程序分解为若干个文件,分别编译,或者分步调试,先通过最基本的部分,再逐步扩充。现在要对上面写的基类声明进行调试,检查它是否有错,为此要写出main函数。实际上它是一个测试程序。intmain()pointp(3.5,6.4);建立point类对象pcoutx=p.getx(),y=pgety()endl;/输出p的坐标值psetpoint(8.5,68)重新设置p的坐标值coutp(new):pendl;用/重载运算符“输出p点坐标return0;getx和gety函数声明为常成员函数,作用是只允许函数引用类中的数据,而不允许修改它们,以保证类中数据的安全。数据成员x和y声明为protected,这样可以被派生类访问(如果声明为private派生类是不能访问的)。程序编译通过,运行结果为:x=3.5,y=6.4p(new):8.5,6.8测试程序检查了基类中各函数的功能,以及运算符重载的作用,证明程序是正确的。声明派生类circle在上面的基础上,再写出声明派生类circle的部分:classcircle:publicpoint/cir是lpoint类的公用派生类public:circle(floatx=0,floaty=0,floatr=构造函数voidsetradius(float)设置半径值floatgetradius()const读取半径值floatarea()const计算面积friendostreamoperator(ostream,constcircle重载运算符“”private:floatrad定义/构造函数,对圆心坐标和半径初始化circle:circle(floata,floatb,floatr):point(a,b),radius(设置半径值voidcircle:setradius(floatr)radius=f;3!/半径值floatcircle:area()constreturn3.14159*radius*radii|li载运算符“,使之按规定的形式输出圆的信息ostreamoperator(ostreamoutput,constcirclec)outputcenter=c.x,c.y,r=c.radius,area=c.area()endl;returnout为了测试以上circlecircle:getradius()constreturnradiu计算/圆面积float类的定义,可以写出下面的主函数:intmain()circlec(3.5,6.4,5.2);/建立circle类对象c,并给定圆心坐标和半径coutoriginalcircle:nx=c.getx(),y=c.gety(),r=c.getradius(),area=c.area()endl;输出圆心坐标、半径和面积c.setradius(75)设/置半径值c.setpoint(5,5)设置圆心坐标值x,ycoutnewcircle:nc;/用重载运算符“输出圆对象的信息pointpref=c;/prlfpoint类的引用变量,被c初始化coutpref:pref输出pref的信息return0;程序编译通过,运行结果为:originalcircl输出原来的圆的数据)x=3.5,y=6.4,r=5.2,area=84.9486newcircle:输出修改后的圆的数据)center=5,5,r=7.5,area=176.714pref:5,5输出圆的圆心点”的数据)可以看到,在point类中声明了一次运算符“重载函数,在circle类中又声明了一次运算符“,”两次重载的运算符“内”容是不同的,在编译时编译系统会根据输出项的类型确定调用哪一个运算符重载函数。main函数第7行用“cout输出c,调用的是在circle类中声明的运算符重载函数。请注意main函数第8行:pointpref=c;定义了point类的引用变量pref,并用派生类circle对象c对其初始化。前面我们已经讲过,派生类对象可以替代基类对象为基类对象的引用初始化或赋值(详情请查看:)。现在circle是point的公用派生类,因此,pref不能认为是c的别名,它得到了c的起始地址,它只是c中基类部分的别名,与c中基类部分共享同一段存储单元。所以用coutpref”出时,调用的不是在circle中声明的运算符重载函数,而是在point中声明的运算符重载函数,输出的是点”的信息,而不是“圆”的信息。声明circle的派生类cylinder前面已从基类point派生出circle类,现在再从circle派生出cylinder类。classcylinder:publiccircle/cylii是erircle的公用派生类public:cylinder(floatx=0,floaty=0,floatr=0,floath=0);柱高float/构造函数voidsetheight(float)设;置/getheight()const;读取圆柱高loatarea()const:计算圆表面积floatvolume()const;计算圆柱体积friendostreamoperator(ostream,constcylinder重/载运算符protected:floatheight;/圆柱高/定义构造函数cylinder:cylinder(floata,floatb,float圆/r,floath):circle(a,b,r),height(设Bicylinder:setheight(floath)height=h读取圆柱高floatcylinder:area()constreturn2*circle:area()+2*314159*radius*height计算/圆柱体积floatcylinder:volume()constreturncircle:area()*height;ostreamoperator(ostreamoutput,constcylindercy)outputcenter=cyx,cyy,r=cyradius,h=cyheightnarea=cylinder:getheight()constreturnheight计算表面积floatcy.area(),volume二cy.volume()endl;returnoutput!载/运算符“可以写出下面的主函数:intmain()cylindercy1(3.5,6.4,5.2,10)定义cylinder类对象cy1coutnoriginalcylinder:nx=cy1.getx(),y=cy1.gety(),r=cy1.getradius(),h=cy1.getheight()narea=cy1.area(),volume=cy1.volume()endl;/用系统定义的运算符“输出cy1的数据cy1.setheight(15);/设置圆柱高cy1.setradius(75)设:圆半径cyl.setpoint(5,5)设/置圆心坐标值x,ycoutnnewcylinder:ncyl用/重载运算符“输出cyl的数据pointpref=cy1;/pre是point类对象的引用变量coutnprefasapoint:pref;/p作e为一个点”输出circlecref=cy1;/cre是circle类对象的引用变量coutncrefasacircle:cref;/cre作为一个”输出return0;运行结果如下:originalcylinder输出cyl的初始值)x=3.5,y=6.4,area=496.623,newcylinder:r=5.2,h=10圆心坐标x,yo半径r,高h)volume=849.486(圆柱表面积area和体积volume)输出cyl的新值)center=5,5,r=75,h=1以5,5形式输出圆心坐标)area=1060.29,volume=2650.72(圆柱表面积area和体积volume)prefasapoint:5,5(pre为一个点”输出)crefasacircle:center=5,5,r=75,area=176.714作c为一个“圆”输出)说明:在cylinder类中定义了area函数,它与circle类中的area函数同名,根据前面我们讲解的同名覆盖的原则(详情请查看:),cyl.area()调用的是cylinder类的area函数求圆柱表面积),而不是circle类的area函数(圆面积)。请注意,这两个area函数不是重载函数,它们不仅函数名相同,而且函数类型和参数个数都相同,两个同名函数不在同个类中,而是分别在基类和派生类中,属于同名覆盖。重载函数的参数个数和参数类型必须至少有一者不同,否则系统无法确定调用哪一个函数。main函数第9行用“coutcyl来输出cyl,此时调用的是在cylinder类中声明的重载运算符“,按在重载时规定的方式输出圆柱体cyl的有关数据。main函数中最后4行的含义与在定义circle类时的情况类似。pref是point类的引用变量,用cyl对其初始化,但它不是cyl的别名,只是cyl中基类point部分的别名,在输出pref时是作为一个point类对象输出的,也就是说,它是一个点”同样,cref是circle类的引用变量,用cyl对其初始化,但它只是cyl中的直接基类circle部分的别名,在输出cref时是作为circle类对象输出的,它是一个圆”,而不是一个“圆柱体”。从输出的结果可以看出调用的是哪个运算符函数。在本例中存在静态多态性,这是运算符重载引起的(注意3个运算符函数是重载而不是同名覆盖,因为有一个形参类型不同)。可以看到,在编译时编译系统即可以判定应调用哪个重载运算符函数。【篇二:c中实现多态的例子】C+中的多态(虽然多态不是c+所特有的,但是C+中的多态确实是很特殊的)分为静多态和动多态(也就是静态绑定和动态绑定两种现象),静动的区别主要在于这种绑定发生在编译期还是运行期,发生在编译期的是静态绑定,也就是静多态;发生在运行期的则是动态绑定,也就是动多态。静多态可以通过模板和函数重载来实现(之所说C+中的多态主要还是因为模板这个东西),下面举两个例子:1)templatetypenamettmax(consttlsh,consttrhs)return(lshrhs)?lsh:rhs;返回两个任意类型对象的最大值(对象),前提是该类型能够使用运算符进行比较,并且返回值是bool类型。使用:inta=3;intb=4;coutmax(a,b)endl;floatc=2.4;floatd=1.2;coutmax(c,d)endl;输出结果为:42.4这种绑定发生在编译期,这是由于模板的实例化是发生在编译期的,即在编译时编译器发现你调用max(a,b)时就自动生成一个函数intmax(constintlsh,constintrhs)return(lshrhs)?lsh:rhs;即将所有的t替换成int;当你调用max(c,d)时就自动生成一个函数floatmax(constfloatlsh,constfloatrhs)return(lshrhs)?lsh:rhs;之所以说开始的函数定义是,就是因为他就像个模子似的,你可以用铝作为原料也可以用石膏或者铜。2)函数重载:intmax(inta,intb)return(ab)?a:b;intmax(inta,intb,intc)returnmax(max(a,b),c);两个函数名称一样,参数类型或个数不完全相同,返回值一样(这个不重要)。使用:inta=3,b=4,c=5;coutmax(a,b)endl;coutmax(a,b,c)endl;输出结果为:45确定函数的过程也发生在编译器,当你使用max(a,b),编译器发现只有两个参数,那么就调用只有两个参数的函数版本,当使用max(a,b,c肘,编译器则使用有3个参数的版本。通过上面的两个例子,你还可以使用更为方便的重载:templatetypenamettmax(consttlsh,consttrhs)return(lshrhs)?lsh:rhs;templatetypenamettmax(constta,consttb,consttc)returnmax(max(a,b),c);使用floata=3.6,b=1.2,c=7.8;coutmax(a,b,c)endl;输出:7.8通过参数个数和类型,编译器自动生成和调用对应得函数版本!动多态则是通过继承、虚函数(virtual、指针来实现。classapublic:virtualvoidfunc()constcoust“a:func()”endl;classb:publicapublic:virtualvoidfunc()constcoust“b:func()”endl;使用:aa*=b();a-func();输出:b:func()编译期是不调用任何函数的,编译器编译到a-func(时只是检查有没有语法问题,经过检查没有。编译器并不知道调用的是a版本的func()还是b版本的func(),由于a是一个指向b对象的指针,所以a只知道它指向的是一个a类型(或者能转换成a类型)的对象。通常集成体系就说明了(由于是公有继承)b是一种a。在运行期,a要调用a所指向对象的func()函数,就对它指向的对象下达调用funcO的命令,结果a所指向的是一个b对象,这个对象就调用了自己版本(b版)的funcO函数,所以输出时b:func()总结:在编译期决定你应该调用哪个函数的行为是静态绑定(static-binding),这种现象就是静多态。
展开阅读全文
相关资源
相关搜索

最新文档


当前位置:首页 > 办公文档 > 解决方案


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!