您好,欢迎访问三七文档
第7章多态性与虚函数7.1多态性的概念7.2静态关联与动态关联7.3虚函数7.4纯虚函数与抽象类在C++程序设计中,多态性是指具有不同功能的函数可以用同一个函数名,这样就可以用一个函数名调用不同内容的函数。或指发出同样的消息被不同类型的对象接收时导致完全不同的行为。消息:对成员函数的调用不同的行为:不同的函数实现7.1多态性的概念多态的实现函数重载(静态多态)运算符重载(静态多态)虚函数(动态多态)例7-1函数重载是多态性的一种简单形式,它是指允许在相同的作用域内,相同的函数名对应着不同的实现。函数重载的条件是要求函数参数的类型或个数有所不同。对成员函数的重载有以下三种表达方式:1、在一个类中重载;2、在不同类中重载;3、基类的成员函数在派生类中重载。函数重载具有相同名字的重载函数是在编译时区分的,有以下三种区分方法:1、根据参数的特征加以区别,例如:show(int,char);show(char*,float);2、使用类作用域符“::”加以区分,例如:Circle::show();Point::show();3、根据类对象加以区分,例如:acirle.show()调用Circle::show()apoint.show()调用Point::show()除了函数重载这种简单形式之外,C++还提供了一种更为灵活的特征机制——虚函数。虚函数允许函数调用与函数体的联系在运行时才给出。当需要同一接口、多种实现时,这种功能显得尤其重要。在讲述虚函数的概念之前,先介绍子类型及静态联编和动态联编的相关内容。虚函数的引入(动态多态)要研究的问题是:当一个基类被继承为不同的派生类时,各派生类可以使用与基类成员相同的成员名,如果在运行时用同一个成员名调用类对象的成员,会调用哪个对象的成员?举例根据类型适应性,在公有继承方式下,指向基类和派生类的指针变量是相关的。如果B是基类,D是从B公有派生出来的派生类,则在C++中,指向基类B的指针P也可以指向派生类D。当P指向派生类D的对象时,利用指针P可以访问从基类B继承的成员,但派生类D自己定义的成员不能用P访问(除非用显式类型转换)。例如:下面是指向基类对象的指针指向派生类对象,而访问从基类继承的成员的例子。#includeiostream.h#includestring.hclassB{charname[80];public:voidput_name(char*s){strcpy(name,s);}voidshow_name(){coutname“\n”;}};classD:publicB{charphone_num[80];public:voidput_phone(char*num){strcpy(phone_num,num);}voidshow_phone(){coutphone_num“\n”;}};main(){B*p;BBobj;D*dp;DDobj;p=&Bobj;P-put_name(“ZhangFang”);p=&Dobj;p-put_name(“WangMing”);//访问从基类继承的成员函数Bobj.show_name();Dobj.show_name();dp=&Dobj;dp-put_phone(“83768493”);//访问自己的成员dp-show_phone();p-show_phone();//error//指向基类指针不能访问派生类定义的成员((D*)P)-show_phone();//强行类型转换}结果:ZhangFangWangMing8376849383768493注意:希望用基类指针访问其公有派生类的特定成员,必须将基类指针用显式类型转换为派生类指针。根据类型适应性的原则,一个指向基类的指针可用来指向以公有派生的任何对象是C++实现运行时多态性的关键。CommissionEmployee•classCommissionEmployee•{•public:•CommissionEmployee(conststring&,conststring&,conststring&,•double=0.0,double=0.0);•voidsetFirstName(conststring&);//setfirstname•stringgetFirstName()const;//returnfirstname•voidsetLastName(conststring&);//setlastname•stringgetLastName()const;//returnlastname•voidsetSocialSecurityNumber(conststring&);//setSSN•stringgetSocialSecurityNumber()const;//returnSSN•voidsetGrossSales(double);//setgrosssalesamount•doublegetGrossSales()const;//returngrosssalesamount•voidsetCommissionRate(double);//setcommissionrate•doublegetCommissionRate()const;//returncommissionrate•doubleearnings()const;//calculateearnings•voidprint()const;//printCommissionEmployeeobject•private:•stringfirstName;•stringlastName;•stringsocialSecurityNumber;•doublegrossSales;//grossweeklysales•doublecommissionRate;//commissionpercentage•};//endclassCommissionEmployeeBasePlusCommissionEmployee•classBasePlusCommissionEmployee:publicCommissionEmployee•{public:•BasePlusCommissionEmployee(conststring&,conststring&,•conststring&,double=0.0,double=0.0,double=0.0);•voidsetBaseSalary(double);//setbasesalary•doublegetBaseSalary()const;//returnbasesalary•doubleearnings()const;//calculateearnings•voidprint()const;//printBasePlusCommissionEmployeeobject•private:•doublebaseSalary;//basesalary•};//endclassBasePlusCommissionEmployee派生类指针指向基类对象•intmain()•{•CommissionEmployeecommissionEmployee(•Sue,Jones,222-22-2222,10000,.06);•BasePlusCommissionEmployee*basePlusCommissionEmployeePtr=0;•//aimderived-classpointeratbase-classobject•//Error:aCommissionEmployeeisnotaBasePlusCommissionEmployee•basePlusCommissionEmployeePtr=&commissionEmployee;•return0;•}//endmain基类对象指针指向派生类对象这种情况下,要访问派生类的成员函数,要做://强制类型转换•如:((BasePlusCommissionEmployee*)commissionEmployeePtr)-print();确定调用的具体对象的过程称为关联(binding)。在这里是指把一个函数名与一个类对象捆绑在一起,建立关联。一般地说,关联指把一个标识符和一个存储地址联系起来。7.2静态关联与动态关联在编译时即可确定其调用的函数,其过程称为静态关联(staticbinding),由于是在运行前进行关联的,故又称为早期关联(earlybinding)。在运行阶段把虚函数和类对象“绑定”在一起的,此过程称为动态关联(dynamicbinding)。这种多态性是动态的多态性,即运行阶段的多态性。由于动态关联是在编译以后的运行阶段进行的,因此也称为滞后关联(latebinding)。多态性分为两类:静态多态性和动态多态性。(1)静态多态:(例7-1)(在程序编译时系统就能决定调用的是哪个函数),因此静态多态性又称编译时的多态性。静态多态是通过函数重载来实现的。(2)动态多态(在例7-1基础上加virtual)是在程序运行过程中才动态地确定操作所针对的对象。它又称运行时的多态性。动态多态性是通过虚函数(virtualfunction)实现的。在类的继承层次结构中,在不同的层次中可以出现名字相同、参数个数和类型都相同而功能不同的函数。编译系统按照同名覆盖的原则决定调用的对象。例7.2基类与派生类中有同名函数。7.3虚函数7.3.1虚函数的作用虚函数的作用:允许在派生类中重新定义与基类同名的函数,并且通过基类指针或引用来访问基类和派生类中的同名函数,实现动态多态的效果。虚函数是一种非静态的成员函数,定义格式如下:virtual类型说明符函数名(参数表){//函数体}其中,virtual是关键字。如果某个类中的一个成员函数被说明为虚函数,该成员函数可能在派生类中存在着不同的实现版本。由于存在有虚函数,编译器将进行动态联编,使调用虚函数的对象在运行时确定,以实现动态联编的多态性。例如:使用虚函数将上例改为动态联编的情况,将得到不同的结果#includeiostream.hclassBase{protected:intx;public:Base(inta){x=a;}virtualvoidprint(){cout“Base”x“\n”;}};classFirst_d:publicBase{public:First_d(inta):Base(a){}virtualvoidprint(){cout“Firstderivation\n”x“\n”;}};classSecond_d:publicBase{public:Second_d(inta)=Base(a){}virtualvoidprint(){cout“Secondderivation\n”x“\n”;}};voidmain(){Base*p;Baseobj1(1);First_dobj2(2);Second_dobj3(3);p=&obj1;p-print();p=&obj2;p-print();p=&obj3;p-print();obj2.print();obj3.print();}运行结果:Base1Firstderivation2Secondderivation3Firstderivation2Secondderivation3程序中,p-print();出现了三次,由于p指向的对象不同,每次执行了print()的不同实现版本。实现了“单界面、多实现版本”的思想。基类函数具有虚特性的条件是:1、在基类中,将该函数说明为虚函数(virtual);2、定义基类的公有派生类;3、在基类的公有派生类中重载该虚函数;4、定义指向基类的指针变量,它指向基类的公有派生类的对象。注意:重载虚函数不是一般的重载函数,它要求函数名、返回类型、参数个数、参数类型和顺序完全相同。由于对虚函数
本文标题:c++7 多态性
链接地址:https://www.777doc.com/doc-7028989 .html