《CC++语言程序设计案例教程》课件-第11章多态性与虚函数_第1页
《CC++语言程序设计案例教程》课件-第11章多态性与虚函数_第2页
《CC++语言程序设计案例教程》课件-第11章多态性与虚函数_第3页
《CC++语言程序设计案例教程》课件-第11章多态性与虚函数_第4页
《CC++语言程序设计案例教程》课件-第11章多态性与虚函数_第5页
已阅读5页,还剩55页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1第十一章多态性与虚函数

C

语言程序设计案例教程12/23/20242案例一函数重载1.问题描述设计程序实现同一个函数Area根据提供参数的个数不同,分别实现圆和矩形面积的计算。2.问题分析注意本案例中函数重载时的依据是什么,函数的类型、参数个数、参数类型等的不同。本例中函数重载(计算面积的函数,输入一个数,视为圆形;输入两个数,视为矩形,分别计算面积)12/23/202433. C++ 代码#include<iostream.h>#definePI3.14floatArea(floatr){returnPI*r*r;}floatArea(floata,floatb){returna*b;}voidmain(){floatr,a,b; //r作为圆的半径,a、b分别作为矩形的长和宽。

cout<<"请输入圆的半径";cin>>r;cout<<"请输入矩形的长:";cin>>a;cout<<"请输入矩形的宽:";cin>>b;cout<<"圆的面积为:"<<Area(r)<<"矩形的面积为:"<<Area(a,b)<<endl;//Area(r)和Area(a,b)参数个数和类型不同}4.程序运行结果请输入圆的半径19请输入矩形的长:5请输入矩形的宽:4圆的面积为:1133.54矩形的面积为:2012/23/2024411.1多 态 性 概 述

用同一个名字来访问不同函数的性质被称作多态性。也就是说不同对象收到相同的消息时,产生不同的动作,比如让狗和鱼不同的两个对象移动,则狗会走,鱼会游。使用多态性,一些相似功能的函数可用同一个名字来定义,这不仅使得概念上清晰,还可达到动态链接的目的,实现运行时的多态性。在C++ 中,多态性的实现和联编这一概念有关。一个源程序经过编译、链接,成为可执行文件的过程就是联编。联编分为两类:静态联编和动态联编。静态联编,也称前期联编,是指在运行之前就完成的编译;动态联编,也称后期联编,是指在程序运行时才完成的编译。静态联编支持的多态性称为编译时多态性,也称静态多态性。在C++ 中,编译时多态性是通过函数重载和运算符重载实现的。动态联编支持的多态性称为运行时多态性,也称动态多态性。在C++ 中,运行时多态性是通过继承和虚函数来实现的。12/23/2024511.2函数重载

编译时的多态性可以通过函数重载来实现。函数重载有两种情况:一是参数有所差别的重载,意义在于它能用同一个名字访问一组相关的函数,在前面我们已经做过介绍;再一个是函数所带参数完全相同,只是它们属于不同的类,这些类之间一般有继承和派生关系。12/23/20246例11.1在基类和派生类中函数重载。#include<iostream.h>classBase{//基类

intx,y;public:Base(inta,intb){x=a;y=b;}voiddisplay()//基类中的display()函数

{cout<<"执行基类中的display()函数"<<endl;cout<<x<<","<<y<<endl;}};classDerived:publicBase{//派生类Derived,Base公有派生出Derived类

intz;public:Derived(inta,intb,intc):Base(a,b){z=c;}voiddisplay()//派生类中的display()函数

{cout<<"执行派生类中的display()函数"<<endl;cout<<z<<endl;}};12/23/20247main(){Baseb(20,20);Derivedd(8,8,30);b.display();//执行基类中的display()函数

d.display();//执行派生类中的display()函数

d.Base::display();//执行基类中的display()函数}在基类和派生类中进行函数重载时,用以下两种方法可以在编译时区别重载函数:(1)使用对象名加以区分。例如:b.display()和d.display()分别调用类Base和Derived的display()函数。派生类中会隐藏基类中与派生类同名的成员。(2)使用“类名::”加以区分。例如:d.Base::display()调用的是Base的display()函数。12/23/20248案例二运算符重载1.问题描述将运算符“+”重载为复数的成员函数(复数的加法运算)。2.问题分析注意掌握运算符如何重载为类的成员函数方式以及运算符的调用方式。12/23/202493. C++ 代码#include<iostream.h>classcomplex{public:doublereal;doubleimag;complex(doubler=0,doublei=0) //complex的构造函数

{real=r;imag=i;}};complexoperator+(complexco1,complexco2) //运算符+重载为类的成员函数{complextemp;temp.real=co1.real+co2.real;temp.imag=co1.imag+co2.imag;returntemp;}main(){complexcom1(3.1,2.4),com2(1.3,5.3),total1,total2;total1=operator+(com1,com2); //调用运算符函数operater+()的第一种方式

cout<<"real1="<<total1.real<<""<<"imag1="<<total1.imag<<endl;total2=com1+com2; //调用运算符函数operater+()的第二种方式

cout<<"real2="<<total2.real<<""<<"imag2="<<total2.imag<<endl;}4.程序运行结果real1=4.4imag1=7.7real2=4.4imag2=7.712/23/20241011.3运算符的重载在C++ 中,除了可以对函数重载外,还可以对大多数运算符实现重载。自定义的类运算往往用运算符重载函数来实现。运算符重载可以扩充语言的功能,就是将运算符扩充到用户定义的类型上去。运算符重载通过创建运算符函数operator()来实现。为了操作相应类的所有数据成员,可以将运算符重载成类的成员函数,也可以是类的友元函数。12/23/20241111.3.1运算符重载的规则如果有一个复数类complex:classcomplex{public:doublereal;

doubleimag;complex(doubler=0,doublei=0){real=r;imag=i;}};若要把complex的两个对象相加,下面的语句是不能实现的:complexobj1(3.1,2.2),obj2(1.3,4.2),total;total=obj1+obj2;//错误12/23/202412不能实现的原因是类complex的类型不是基本数据类型,而是用户自定义的数据类型,“+”只能实现基本数据类型的加法运算,C++ 无法直接将两个自定义的类对象进行相加。为了表达方便,人们希望能对自定义的类型进行运算,希望内部运算符(如“+”“-”“*”“/”等)在特定的类对象上以新的含义进行解释,即实现运算符的重载。C++ 为运算符重载提供了一种方法,使用以下形式进行运算符重载:typeoperator@(参数表);其中,@表示要重载的运算符,type是返回类型。12/23/202413说明:(1)除了“.”“*”“::”“?:”“#”“##”,其他运算符都可以重载。(2) delete、new、指针、引用也可以重载。(3)运算符函数可以定义为内置函数。(4)用户定义的运算符无法改变运算符原有的优先次序。(5)不可以定义系统定义的运算符集之外的运算符。(6)不能改变运算符的语法结构。在案例二中可以看出,我们定义了一个operator+()函数实现了complex对象的相加。在调用该函数时,可以采用显式调用和隐式调用。operator+()函数是一个非类成员,所以将complex类的数据成员real和imag定义成了公有函数,以方便operator+()函数的访问。这样破坏了complex的数据私有性。因此在重载运算符时通常重载为类的成员函数或友元函数。12/23/20241411.3.2运算符重载为成员函数

成员运算符定义的两种语法形式如下:classX{//…typeoperator@(参数表);

//…};typeX::operator@(参数表){//函数体}其中,type为函数的返回类型,@为所要重载的运算符符号,X是重载此运算符的类名,参数表中罗列的是该运算符所需要的操作数,和一般函数的形参定义一致。在成员运算符函数的参数表中,若运算符是单目的,则参数表为空(调用成员函数的对象作为操作数);若运算符是双目的,则参数表中有一个操作数(调用成员函数的对象作为另一个操作数)。12/23/2024151.双目运算符重载对双目运算符而言,成员运算符函数的参数表中只有一个参数,它作为运算符的右操作数,此时当前对象作为运算符的左操作数,它是通过this指针隐含地传递给函数的。调用时可采用以下两种方式:A@B;//隐式调用,AB都是运算符操作对象A.operator@(B);//显式调用下面是一个双目运算符的例子。12/23/202416例11.2双目运算符重载为成员函数。#include<iostream.h>classcomplex{private:doublereal;doubleimag;public:complex(doubler=0.0,doublei=0.0);complexoperator+(complexc); //重载“+”运算符为复数成员函数

complexoperator-(complexc); //重载“-”运算符为复数成员函数

voiddisplay();};complex::complex(doubler,doublei){real=r;imag=i;}complexcomplex::operator+(complexc){complextemp;temp.real=real+c.real;temp.imag=imag+c.imag;returntemp;}12/23/202417complexcomplex::operator-(complexc){complextemp;temp.real=real-c.real;temp.imag=imag-c.imag;returntemp;}voidcomplex::display(){cout<<real;if(imag>0)cout<<"+";if(imag!=0)cout<<imag<<"i\n";}main(){complexA1(1.9,6.9),A2(0.9,0.9),A3,A4,A5,A6;A3=A1+A2; //对operator+()隐式调用

A4=A1-A2; //对operator-()隐式调用

A1.display();A2.display();A3.display();A4.display();}程序运行结果如下:1.9+6.9i0.9+0.9i2.8+7.8i1+6i12/23/2024182.单目运算符重载对单目运算符而言,成员运算符函数的参数表中没有参数,此时当前对象作为运算符的一个操作数。调用时可采用以下两种方式:@A; //隐式调用A.operator@(); //显式调用下面是一个单目运算符的例子。12/23/202419例11.3单目运算符重载为成员函数。#include<iostream.h>classMyClass{intx,y;public:MyClass(inti=0,intj=0);voidprint();MyClassoperator++(); //定义单目运算符函数};MyClass::MyClass(inti,intj){x=i;y=j;}voidMyClass::print(){cout<<"x:"<<x<<",y:"<<y<<endl;}MyClassMyClass::operator++() //前置++{++x;++y;return*this;}12/23/202420main(){MyClassob(10,20);ob.print();++ob; //隐式调用

ob.print();ob.operator++(); //显式调用

ob.print();}程序运行结果如下:x:10,y:20x:11,y:21x:12,y:2212/23/20242111.3.3运算符重载为友元函数

在C++ 中,还可以把运算符函数定义成某个类的友元函数,称为友元运算符函数。1.友元运算符函数定义的语法形式友元运算符函数在类内声明形式如下:friendtypeoperator@(参数表);类外函数实现形式如下:typeoperator@(参数表){//函数体}与成员函数不同,友元运算符函数是不属于任何类对象的,它没有this指针。若重载的是双目运算符,则参数表中需要两个操作数;若重载的是单目运算符,则参数表中需要一个操作数。12/23/2024222.双目运算符重载当用友元函数重载双目运算符时,两个操作数都要传递给运算符函数,调用时可采用以下两种方式:A@B; //隐式调用operator@(A,B); //显式调用双目友元运算符函数operator@所需要的两个操作数都在参数表中由对象A和B显式调用。下面我们给出一个例子。例11.4双目运算符重载为友元函数代码如下:12/23/202423例11.4双目运算符重载为友元函数代码如下:#include<iostream.h>classcomplex{private:doublereal;doubleimag;public:complex(doubler=0.0,doublei=0.0);friendcomplexoperator+(complexa,complexb); //重载“+”运算符为复数类友元函数

friendcomplexoperator-(complexa,complexb); //重载“-”运算符为复数类友元函数

voiddisplay();};complex::complex(doubler,doublei){real=r;imag=i;}complexoperator+(complexa,complexb){complextemp;temp.real=a.real+b.real;temp.imag=a.imag+b.imag;returntemp;}12/23/202424complexoperator-(complexa,complexb){complextemp;temp.real=a.real-b.real;temp.imag=a.imag-b.imag;

returntemp;}voidcomplex::display(){cout<<real;if(imag>0)cout<<"+";if(imag!=0)cout<<imag<<"i\n";}main(){complexA1(1.9,6.9),A2(0.9,0.9),A3,A4A3=A1+A2;A4=A1-A2;A1.display();

A2.display();A3.display();A4.display();}程序运行结果如下:1.9+6.9i0.9+0.9i2.8+7.8i1+6i12/23/2024253.单目运算符重载当用友元函数重载单目运算符时,需要一个显式的操作数,调用时可采用以下两种方式:@A;//隐式调用operator@(A);//显式调用下面我们给出一个应用例子。12/23/202426例11.5单目运算符重载为友元函数,代码如下:#include<iostream.h>classMyClass{intx,y;public:MyClass(inti=0,intj=0);voidprint();friendMyClassoperator++(MyClass&op); //定义单目运算符“++”函数为友元函数};MyClass::MyClass(inti,intj){x=i;y=j;}voidMyClass::print(){cout<<"x:"<<x<<",y:"<<y<<endl;}MyClassoperator++(MyClass&op) //前置++{++op.x;++op.y;returnop;}12/23/202427main(){MyClassob(10,20);ob.print();++ob; //隐式调用;前置++ob.print();operator++(ob); //显式调用;前置++ob.print();}12/23/202428需要注意的是,使用友元函数重载“++”“--”这样的运算符,可能会出现一些问题。我们回顾一下例11.3用成员函数重载“++”的成员运算符函数的情况。MyClassMyClass::operator++() //前置++{++x;++y;return*this;}由于所有的成员都有一个this指针,this指针指向该函数所属类对象的指针,因此对私有数据x和y的任何修改都将影响实际调用运算符函数的对象。因此例11.3的执行是完全正确的。但是如果像下面那样用友元函数按以下方式改写例11.5的运算符函数,将不会改变main()函数中对象ob的值。12/23/202429MyClassoperator++(MyClassop) //前置++{++op.x;++op.y;returnop;}为了解决以上问题,使用友元函数重载单目运算符“++”和“--”时,应采用引用参数传递操作数,如例11.5,这样形参的任何改变都影响实参,从而保持了两个运算符的原义。12/23/20243011.3.4“++”和“--”的重载我们知道,运算符“++”和“--”作前缀和后缀是有区别的。但是在C++v2.1之前的版本重载“++”或“--”时,不能显示区分是前缀方式还是后缀方式;在C++v2.1及以后的版本中,编辑器可以通过在运算符函数表中是否插入关键字int来区分这两种方式。对于前缀方式 ++ob,可以使用运算符函数重载为:ob.operator++(); //成员函数重载;前置++operator++(X&ob); //友元函数重载,X为要操作的类型;前置++对于后缀方式ob++,可以使用运算符函数重载为:ob.operator++(int); //成员函数重载;后置++operator++(X&ob,int); //友元函数重载;后置++调用时,参数int一般被传递给值0。我们看如下例子。12/23/202431例11.6运算符“++”和“--”作前缀和后缀重载。#include<iostream.h>#include<iomanip.h>classMyClass{

intx1,x2,x3;public:voidinit(inta1,inta2,inta3);voidprint();MyClassoperator++(); //成员函数重载"++"前缀方式原型

MyClassoperator++(int); //成员函数重载"++"后缀方式原型

friendMyClassoperator--(MyClass&); //友元函数重载"--"前缀方式原型

friendMyClassoperator--(MyClass&,int); //友元函数重载"--"后缀方式原型};12/23/202432voidMyClass::init(inta1,inta2,inta3){x1=a1;x2=a2;x3=a3;}voidMyClass::print(){cout<<"x1:"<<x1<<"x2:"<<x2<<"x3:"<<x3<<endl;}MyClassMyClass::operator++(){++x1;++x2;++x3;return*this;}MyClassMyClass::operator++(int){MyClassold;old=*this;x1++;x2++;x3++;returnold;}MyClassoperator--(MyClass&op){--op.x1;--op.x2;--op.x3;returnop;}MyClassoperator--(MyClass&op,int){MyClassold;old=op;op.x1--;op.x2--;op.x3--;returnold;}12/23/202433main(){MyClassobj1,obj2,obj3,obj4;

obj1.init(4,2,5);obj2.init(2,5,9);obj3.init(8,3,8);obj4.init(3,6,7);++obj1;obj2++;--obj3;obj4--;obj1.print();obj2.print();obj3.print();

obj4.print();cout<<"--------------------"<<endl;obj1.operator++();obj2.operator++(0);operator--(obj3);operator--(obj4,0);obj1.print();obj2.print();obj3.print();obj4.print();}12/23/202434程序运行结果如下:x1:5x2:3x3:6x1:3x2:6x3:10x1:7x2:2x3:7x1:2x2:5x3:6--------------------x1:6x2:4x3:7x1:4x2:7x3:11x1:6x2:1x3:6x1:1x2:4x3:512/23/202435

案例三虚函数使用1.问题描述设计玩具和玩具车,玩具车由玩具派生,设计输出函数来实现玩具车信息输出。2.问题分析注意掌握虚函数的定义方法、派生类同名成员函数的二义性避免方法、声明成虚函数后同名函数覆盖。12/23/2024363. C++ 代码/*本程序分别定义一个toy基类和toy类的派生类toycar;主函数定义一个基类指针分别指向基类和派生类的对象,通过该指针调用两个类中的虚函数和普通函数,呈现不同结果*/#include<iostream.h>classtoy{public:virtualvoidshowname() //定义虚函数showname(){cout<<"Thisisatoy.\n";}voidAskingprice() //定义Askingprice(){cout<<"Howmuchisthistoy?\n";}};classtoycar:publictoy{public:voidshowname() //重新定义虚函数showname(){cout<<"Thisisatoycar.\n";}voidAskingprice() //定义Askingprice(){cout<<"Howmuchisthistoycar?\n";}};12/23/202437voidmain(){toyob1,*op1;toycarob2,*op2;op1=&ob1; //基类指针指向基类对象

op1->showname(); //调用基类指针指向的基类对象的虚成员函数

op1->Askingprice(); //调用基类指针指向的基类对象的成员函数

op1=&ob2; //基类指针指向派生类对象

op1->showname(); //调用基类指针指向的派生类对象的虚成员函数,注意输出

op1->Askingprice(); //调用基类指针指向的派生类对象的成员函数,比较和上面输出不同

op2=&ob2; //派生类指针指向派生类对象

op2->showname(); //调用派生类指针指向的派生类对象的虚成员函数,注意输出

op2->Askingprice();//调用派生类指针指向的派生类对象的成员函数,比较和上面输出不同}12/23/2024384.程序运行结果Thisisatoy.Howmuchisthistoy?Thisisatoycar.Howmuchisthistoy?Thisisatoycar.Howmuchisthistoycar?12/23/20243911.4虚函数

虚函数是重载的另一种表现形式。虚函数允许函数调用与函数体之间的联系在程序运行时才建立,也就是在运行时才决定如何动作,即所谓的动态联编。12/23/20244011.4.1引入派生类后的对象指针

引入派生类后,由于派生类是由基类派生出来的,因此指向基类和派生类的指针也是相关的。其特点如下:(1)声明为指向基类对象的指针可以指向它的公有派生的对象,但不允许指向它的私有派生对象。(2)允许将一个声明为指向基类的指针指向其公有派生类的对象,但是不能将一个声明为指向派生类对象的指针指向其基类的对象。(3)声明为指向基类对象的指针,当其指向其公有派生类对象时,只能用它来直接访问派生类中从基类继承来的成员,而不能直接访问公有派生类中定义的成员。12/23/202441例11.7基类指针指向派生类。#include<iostream.h>classBase{inta,b;public:Base(intx,inty){a=x;b=y;}voiddisplay(){cout<<"Base--------\n";cout<<a<<""<<b<<endl;}};12/23/202442classDerived:publicBase{intc;public:Derived(intx,inty,intz):Base(x,y){c=z;}voiddisplay(){cout<<"Derived---------\n";cout<<c<<endl;}};voidmain(){Baseob1(10,20),*op;Derivedob2(30,40,50);

op=&ob1;op->display();op=&ob2;op->display();}12/23/202443程序运行结果如下:Base--------1020Base--------3040从程序运行的结果可以看出,虽然执行了语句op=&ob2后,指针op已经指向了对象ob2,但是它所调用的函数仍然是其基类对象的display(),显然这不是我们所希望的,我们希望这时调用的函数是Derived的display()。为了达到这个目的,我们可以将函数display()声明为虚函数。12/23/20244411.4.2虚函数的定义及使用

在例11.7中,使用对象指针的目的是为了表达一种动态多态性,即当时针指向不同对象时执行不同的操作,但该例中并没有起到这种作用。要想实现这种动态多态性,我们引入虚函数的概念。虚函数就是在基类中被关键字virtual说明,并在派生类中重新定义的函数。在派生类中重新定义时,其函数原型,包括返回类型、函数名、参数个数与参数类型的顺序,都必须与基类中的原型完全相同。虚函数这种机制是在派生类中会将继承自基类的同名虚函数进行覆盖,原有继承的函数将不复存在,以崭新的形式覆盖原函数;如果不是虚函数,将不会覆盖,产生新的同名函数,在派生类中引用新的同名函数,会隐藏基类的同名函数,在派生类中还可以调用基类隐藏的同名函数,只是要在该函数前面加基类的域标识符。虚函数只能在类中使用,属于类的成员函数,但不能是构造函数。另外,虚函数属于动态联编。12/23/202445我们使用虚函数改写例11.7。例11.8使用虚函数实现动态多态性。#include<iostream.h>classBase{inta,b;public:Base(intx,inty){a=x;b=y;}virtualvoiddisplay()//定义虚函数display(){cout<<"Base--------\n";cout<<a<<""<<b<<endl;}};classDerived:publicBase{

intc;public:Derived(intx,inty,intz):Base(x,y){c=z;}voiddisplay()//重新定义虚函数display(){cout<<"Derived---------\n";cout<<c<<endl;}};12/23/202446voidmain(){Baseob1(10,20),*op;Derivedob2(30,40,50);

op=&ob1;op->display();op=&ob2;op->display();}12/23/202447程序运行结果如下:Base--------1020Derived---------50从程序运行的结果可以看出,执行了语句“op=&ob2;”后,基类指针op已经指向了对象ob2,它所调用的函数仍然是Derived的display(),达到了我们的要求。12/23/202448说明:(1)在基类中,用关键字virtual可以将其public或protected部分的成员函数声明为虚函数。在派生类对基类中声明的虚函数进行重新定义时,关键字virtual可以写也可以不写。(2)虚函数被重新定义时,其函数的原型与基类中的函数原型必须完全相同。(3)一个虚函数无论被公有继承多少次,它仍然保持虚函数的特性。(4)虚函数必须是其所在类的成员函数,而不能是静态成员函数,因为虚函数调用要靠特定的对象来决定该激活哪个函数。但是虚函数可以在另一个类中被声明为友元函数。12/23/20244911.4.3虚析构函数构造函数不能是虚函数,但析构函数可以是虚函数。我们看一个例子。例11.9析构函数定义不当造成内存泄露。#include"iostream.h"classA{public:int*a;A(){a=new(int);}virtualvoidfunc1(){}~A(){deletea;cout<<"deletea"<<endl;}};classB:publicA{public:int*b;B(){b=new(int);}virtualvoidfunc1(){}~B(){deleteb;cout<<"deleteb"<<endl;}};voidmain(){A*pb=newB();deletepb;}12/23/202450程序运行结果如下:deletea在main函数中,创建了一个B类对象。当B对象创建时,调用的是B类的构造函数。但是,当对象析构时,却调用的是A类的析构函数,B类的析构函数没有被调用,因而发生了内存泄漏,这是我们不希望看到的。造成这种问题的原因是:当A类指针指向的内存单元(即B类对象的数据)被释放时,编译器看到指针类型是A类的,所以调用A类的析构函数。其实,这个时候我们需要调用指针所指向的对象类型的析构函数是B类析构函数。虚函数能够满足这个要求。因此,这里我们要使用虚析构函数来解决上面遇到的问题。12/23/202451例11.10虚析构函数的使用。#include"iostream.h"classA{public:int*a;A(){a=new(int);}virtualvoidfunc1(){}virtual~A(){deletea;cout<<"deletea"<<endl;}};classB:publicA{public:int*b;B(){b=new(int);}virtualvoidfunc1(){}virtual~B(){deleteb;cout<<"deleteb"<<endl;}};voidmain(){A*pb=newB();deletepb;}12/23/202452程序运行后得到我们所希望的结果:deletebdeletea从以上程序中我们还可以看到:虚析构函数的工作过程与普通虚函数不同,普通虚函数只是调用相应层上的函数,而虚析构函数是先调用相应层上的析构函数,然后逐层向上调用基类的析构函数。12/23/202453案例四纯虚函数与抽象类

1.问题描述定义一个抽象基类shape,由它派生出两个派生类:ciecle(圆形)、triangle(三角形),用一个函数displayarea分别输出以上两个图形的面积。要求用基类的指针,分别使它指向一个派生类的对象。2.问题分析注意掌握纯虚函数的定义方法和使用特点。12/23/2024543. C++ 代码/*本程序分别定义一个shape基类及其纯虚函数displayarea和shape类的两个派生类circle与triangle,并分别在两个类中实现displayarea;主函数定义一个基类指针分别指向基类和派生类的对象,通过该指针调用两个派生类对象中的虚函数*/#include<iostream.h>classshape{public:virtualvoiddisplayarea()=0;//定义纯虚函数displayarea()};classcircle:publicshape{private:floatR;public:circle(floatr){R=r;}voiddisplayarea() //定义实现voiddisplayarea(){cout<<"圆面积为:"<<3.14*R*R<<endl;}};12/23/202455classtriangle:publicshape{private:floatH,W;public:triangle(floath,floatw){H=h;W=w;}voiddisplayarea() //定义实现voiddisplayarea(){cout<<"三角形面积为:"<<0.5*H*W<<endl;}};voidmain(){shape*pshape;circlecir(10);pshape=○

pshape->displayarea();triangletri(20,10);pshape=&tri;pshape->displayarea();}4.程序运行结果圆面积为:314三角形面积为:10012/23/20245611.5纯虚函数与抽象类有

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论