第9章多态性和虚函数.

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

第9章多态性和虚函数9.1多态性的概念多态性是指不同类的对象对于同一消息的处理具有不同的实现。多态性在C++中表现为同一形式的函数调用,可能调用不同的函数实现。从系统实现的角度看,C++的多态性分为两类,一类称为编译时刻多态性,另一类称为运行时刻多态性,也称动态多态性。9.1.1编译时刻的多态性C++编译时多态性通过重载(函数重载和运算符重载)来实现【例9.1】编译时刻的多态性——运算符重载:下面这段程序建立Data类和T_Data类,并重载运算符“+=”,使之能用于相应类对象的运算。#includeiostreamusingnamespacestd;classData{public:Data(intx=0,inty=0);//缺省构造函数voidset_xy(intx,inty);intget_X()const;intget_Y()const;longnorm();~Data(){};//析构函数Data&operator+=(Data&add)//重载运算符+={m_X+=add.m_X;m_Y+=add.m_Y;return*this;//返回当前对象}protected:intm_X;intm_Y;};classT_Data:publicData{public:T_Data(intx=0,inty=0,intz=0);voidset_xyz(intx,inty,intz);intget_Z();longnorm();T_Data&operator+=(T_Data&add){m_X+=add.m_X;m_Y+=add.m_Y;m_Z+=add.m_Z;return*this;//返回当前对象}protected:intm_Z;};intmain(){Datad1(10,20);Datad2;T_Datad3(10,20,30);T_Datad4;d2.set_xy(20,40);d4.set_xyz(5,10,15);coutd1=(d1.get_X(),d1.get_Y())endl;coutd2=(d2.get_X(),d2.get_Y())endl;d2+=d1;//调用Data类的重载运算符:+=coutd3=(d3.get_X(),d3.get_Y(),;coutd3.get_Z())endl;coutd4=(d4.get_X(),d4.get_Y(),;coutd4.get_Z())endl;d4+=d3;//调用T_Data类的重载运算符:+=}9.1.2运行时刻的多态性运行时刻多态性的实现是指在程序运行过程中根据具体情况来确定调用的是哪一个函数,它是通过动态联编机制实现的【例9.2】运行时刻的多态性仍然用【例9.1】中定义的Data类和T_Data类,main函数如下://*************ex9_2.cpp*************intmain(){Data*p;T_Datad3(10,20,30);coutd3=(d3.get_X(),d3.get_Y(),;coutd3.get_Z())endl;p=&d3;//用基类指针指向派生类对象coutd3'snormis(*p)p-norm()endl;coutd3'snormis(d3)d3.norm()endl;return0;}程序运行的结果如下图。运行时刻的多态性是面向对象的一个非常重要的特征,再来看一个在结构化编程中的例子:【例9.3】下面这段程序是利用多分支结构编程模拟实现绘制图形的函数。//********ex9_3.cpp*********voiddraw(intobj_figure){switch(obj_figure)case0://rectangledraw_rectangle();//cout”drawrectangle”endl;break;case1://triangledraw_triangle();//cout”drawtriangle”endl;break;case2://circledraw_circle();//coutdraw_circleendl;break;}这种编程方式使得程序的可维护性和可扩充性都变得很差。那么有没有更好的方法实现上述例子?看看下面的程序段:voiddraw(void*f){(*f)();}9.2虚函数虚函数的作用虚函数从表现形式看是指那些被virtual关键字修饰的成员函数。类的一个成员函数如果被说明为虚函数,表明它目前的具体实现仅是一种适用于当前类的实现,而在该类的继承层次链条中有可能重新定义这个成员函数的实现,即这个虚函数可能会被派生类的同名函数所覆盖(override)。例:使用虚函数的例子#includeiostreamusingstd::cout;usingstd::endl;classfigure{public:virtualvoiddraw()//将draw()定义为虚函数{coutdrawfigureendl;}};classrectangle:publicfigure{voiddraw(){coutdrawrectangleendl;}};classtriangle:publicfigure{voiddraw(){coutdrawtriangleendl;}};intmain(){figure*f;rectangler1;trianglet1;f=&r1;//基类指针f指向派生类对象r1f-draw();//调用r1的成员函数draw()f=&t1;//基类指针f指向派生类对象t1f-draw();//调用t1的成员函数draw()return0;}程序运行结果:虚函数的使用虚函数的实现机制和调用方式与非虚函数不同,虚函数的使用需要注意以下几点:1.虚函数的声明只能将类的成员函数声明为虚函数,而不能将类外的普通函数声明为虚函数。虚函数的作用是允许在派生类中对基类的虚函数重新定义,因而它只能用于类的继承层次结构中。2.虚函数的访问权限派生类中虚函数的访问权限并不影响虚函数的动态联编,如下面的例9.5,其中派生类CDerived中重新定义了虚函数F4(),在程序的运行中由于虚函数的机制,在CBase::F3()中调用F4()时会调用CDerived::F4(),而该函数的访问权限是私有的。3.成员函数中调用虚函数在类的成员函数中可以直接调用相应类中定义或重新定义的虚函数,分析这类函数的调用次序时要注意成员函数的调用一般是隐式调用,应该将其看成是通过this指针的显式调用。【例9.5】在成员函数中调用虚函数//*********ex9_5.cpp***********#includeiostreamusingnamespacestd;classCBase{public:voidF1(){cout=CBase-F1=;F2();}voidF2(){coutCBase-F2=;F3();}virtualvoidF3(){coutCBase-F3=;F4();//即this-F4()}virtualvoidF4(){coutCBase-F4=;}};classCDerived:publicCBase{private:virtualvoidF4(){coutDerived-F4=outendl;}public:voidF1(){cout=Derived-F1=;CBase::F2();}voidF2(){cout=Derived-F2=;F3();//即this-F3()}};intmain(){CBase*pB;CDerivedObj;程序运行结果:pB=&Obj;pB-F1();Obj.F1();return0;}9.3纯虚函数与抽象类纯虚函数在程序设计中,通常会在类层次的顶层以虚函数的形式给出该类层次所提供的某些操作的统一接口,由于层次较高,有些操作无法(也无必要)给出具体的实现,对于这种情况可以不对虚函数的实现进行定义,而将它们说明为纯虚函数。纯虚函数是在声明虚函数时被“初始化”为0的函数。声明纯虚函数的一般形式是:virtual函数类型函数名(参数表列)=0;抽象类具有纯虚函数的类无法用于创建对象,因为它的纯虚函数无函数体,所以又把这种含有纯虚函数的类称为抽象类。抽象类的主要作用是为一个族类提供统一的公共接口,用户在这个基础上根据自己的需要定义出功能各异的派生类,以有效地发挥多态的特性。使用抽象类时应注意以下问题:⑴抽象类只能用作其它类的基类,不能建立抽象类的对象。因为它的纯虚函数没有定义功能。⑵抽象类不能用作参数类型、函数的返回类型或显式转换的类型。⑶可以声明抽象类的指针和引用,通过它们,可以指向并访问派生类对象,从而访问派生类的成员。⑷如果在抽象类所派生出的新类中对基类的所有纯虚函数进行了定义,那么这些函数就被赋予了功能,可以被调用。这个派生类就不是抽象类,而是可以用来定义对象的具体类。如果在派生类中没有对所有纯虚函数进行定义,则此派生类仍然是抽象类,不能用来定义对象。9.4抽象类的实例一个抽象类就是一个界面。类层次结构是一种逐步递增地建立类的方式。有些抽象类也提供了重要的功能,支持进一步向上构造。类层次结构中的各个类一方面为用户提供了有用的功能,同时也作为实现更高级或者更特殊的类的构造块。这种层次结构对于支持以逐步求精方式进行的程序设计是非常理想的。【例9.10】抽象类实例#includeiostreamusingnamespacestd;classCShape{//定义为一个抽象类,即一个图形界面接口public:virtualdoublearea()const{return0.0;}//定义为虚函数,允许后面覆盖virtualvoidprintShapeName()const=0;//定义为纯虚函数,由派生类负责实现virtualvoiddraw()const=0;//定义为纯虚函数};classCPoint:publicCShape//公有继承CShape{public:CPoint(int=0,int=0);//声明构造函数voidsetPoint(int,int);intgetX()const{returnx;}intgetY()const{returny;}virtualvoidprintShapeName()const//覆盖CShape基类的纯虚函数{coutPoint:;}virtualvoiddraw()const;private:intx,y;};CPoint::CPoint(inta,intb)//CPoint构造函数的实现{setPoint(a,b);}voidCPoint::setPoint(inta,intb){x=a;y=b;}voidCPoint::draw()const{cout[x,y];}classCCircle:publicCPoint{public:CCircle(doubler=0.0,intx=0,inty=0);voidsetRadius(double);doublegetRadius()const;virtualdoublearea()const;virtualvoidprintShapeName()const{coutCircle:;}virtualvoiddraw()const;private:doubleradius;};CCircle::CCircle(doubler,inta,intb):CPoint(a,b){setRadius(r);}voidCCircle::setRadius(doubler){radius=r0?r:0

1 / 30
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功