《C程序设计教程与实验指导杨国兴多态性.ppt》由会员分享,可在线阅读,更多相关《C程序设计教程与实验指导杨国兴多态性.ppt(46页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、C程序设计教程与实验指导杨国兴多态性 Still waters run deep.流静水深流静水深,人静心深人静心深 Where there is life,there is hope。有生命必有希望。有生命必有希望第6章多态性6.1运算符重载6.2运算符重载为类的成员函数6.3运算符重载为类的友元函数6.4虚函数6.1 运算符重载6.1.1问题的提出例例4.34.3的复数类的复数类#include iostream.h#include iostream.hclass CComplex class CComplex private:private:double real;double real
2、;double imag;double imag;public:public:CComplex(double r,double i);CComplex(double r,double i);void Print();void Print();CComplex Add(CComplex c);CComplex Add(CComplex c);CComplex Sub(CComplex c);CComplex Sub(CComplex c);第6章 多态性CComplex CComplex:Add(CComplex c)CComplex temp;temp.real=real+c.real;tem
3、p.imag=imag+c.imag;return temp;CComplex CComplex:Sub(CComplex c)CComplex temp;temp.real=real-c.real;temp.imag=imag-c.imag;return temp;6.1 运算符重载6.1.1问题的提出(续一)void main(void)void main(void)CComplex a(1,2),b(3.0,4.0),c,d;CComplex a(1,2),b(3.0,4.0),c,d;c=a.Add(b);c=a.Add(b);d=a.Sub(b);d=a.Sub(b);cout c=
4、;cout c=;c.Print();c.Print();cout d=;cout d=;d.Print();d.Print();第6章 多态性复数加减法只能调用成员函数实现,复数加减法只能调用成员函数实现,不能使用符号不能使用符号“+”和和“-”,可以通,可以通过重载过重载“+”、“-”运算符,实现如运算符,实现如c=a+b这样的调用方式这样的调用方式运算符重载:运算符重载的实质就是对已有的运算符赋予多重含义,使同一个运算符运算符重载:运算符重载的实质就是对已有的运算符赋予多重含义,使同一个运算符作用于不同类型的数据时,产生不同的行为。运算符重载的实质就是函数重载。作用于不同类型的数据时,产
5、生不同的行为。运算符重载的实质就是函数重载。例例6.16.1用运算符实现复数的加减运算用运算符实现复数的加减运算#includeiostreamusingnamespacestd;classCComplexprivate:doublereal;doubleimag;public:CComplex(doubler=0,doublei=0);voidPrint();CComplexoperator+(CComplexc);CComplexoperator-(CComplexc);CComplex:CComplex(doubler,doublei)real=r;imag=i;第6章 多态性例例6.1
6、6.1(续一)(续一)voidCComplex:Print()cout(real,imag)endl;CComplexCComplex:operator+(CComplexc)CComplextemp;temp.real=real+c.real;temp.imag=imag+c.imag;returntemp;CComplexCComplex:operator-(CComplexc)CComplextemp;temp.real=real-c.real;temp.imag=imag-c.imag;returntemp;第6章 多态性例例6.16.1(续二)(续二)voidmain(void)CC
7、omplexa(1,2),b(3.0,4.0),c,d;c=a+b;d=a-b;coutc=;c.Print();coutd=;d.Print();第6章 多态性该语句相当于对函数该语句相当于对函数operator+(CComplex c)的调用:的调用:“c=a.operator+(b)”,实现两个复数,实现两个复数的加法运算。的加法运算。程序运行结果为:程序运行结果为:c=(4,6)c=(4,6)d=(-2,-2)d=(-2,-2)6.1 运算符重载6.1.2运算符重载的格式与规则1.1.运算符重载的格式运算符重载的格式运算符重载的格式运算符重载的格式 运算符重载为类的成员函数运算符重载为
8、类的成员函数 运算符重载为类的友元函数运算符重载为类的友元函数 运算符重载的为类的成员函数,在类中声明的格式为:运算符重载的为类的成员函数,在类中声明的格式为:运算符重载的为类的成员函数,在类中声明的格式为:运算符重载的为类的成员函数,在类中声明的格式为:函数类型函数类型 operatoroperator运算符(参数表);运算符(参数表);定义该函数的格式:定义该函数的格式:定义该函数的格式:定义该函数的格式:函数类型函数类型 类名类名:operator:operator运算符(参数表)运算符(参数表)函数体;函数体;也可以将重载运算符函数的定义直接写在类中。也可以将重载运算符函数的定义直接写
9、在类中。第6章 多态性6.1 运算符重载6.1.2运算符重载的格式与规则(续)2.2.运算符重载的规则运算符重载的规则运算符重载的规则运算符重载的规则(1 1)除)除“.”.”、“*”“*”、“:”:”、“?:”?:”和和“sizeof”sizeof”等几个运算等几个运算符不能重载外,符不能重载外,C+C+中几乎所有的运算符都可以重载。中几乎所有的运算符都可以重载。(2 2)运算符被重载后,其优先级和结合性不会改变。)运算符被重载后,其优先级和结合性不会改变。(3 3)不能改变运算符操作对象的个数。)不能改变运算符操作对象的个数。第6章 多态性 返 回6.2 运算符重载为类的成员函数6.2.1
10、双目运算符重载双目运算符双目运算符,如果,如果重载为类的成员函数重载为类的成员函数,其,其参数为一个参数为一个,即比,即比运算对象少一个。运算对象少一个。例例6.26.2复数的乘法运算,在上例的基础上添加乘法运算符重复数的乘法运算,在上例的基础上添加乘法运算符重载函数。复数类乘法运算的定义如下:载函数。复数类乘法运算的定义如下:(a+bia+bi)*(x+yix+yi)=a*x-b*y+(a*y+b*x)i=a*x-b*y+(a*y+b*x)i第6章 多态性例例6.26.2复数乘法运算源程序复数乘法运算源程序#includeiostreamusingnamespacestd;classCCom
11、plexprivate:doublereal;doubleimag;public:CComplex(doubler=0,doublei=0);voidPrint();CComplexoperator+(CComplexc);CComplexoperator-(CComplexc);CComplexoperator*(CComplexc);CComplex:CComplex(doubler,doublei)CComplex:CComplex(doubler,doublei)real=r;real=r;imag=i;imag=i;第6章 多态性例例6.26.2(续一)(续一)voidCComple
12、x:Print()cout(real,imag)endl;CComplexCComplex:operator+(CComplexc)CComplextemp;temp.real=real+c.real;temp.imag=imag+c.imag;returntemp;CComplexCComplex:operator-(CComplexc)CComplextemp;temp.real=real-c.real;temp.imag=imag-c.imag;returntemp;第6章 多态性例例6.26.2(续二)(续二)CComplex CComplex:operator*(CComplex c
13、)CComplex temp;temp.real=real*c.real-imag*c.imag;temp.imag=real*c.imag+imag*c.real;return temp;void main(void)CComplex a(1,2),b(3.0,4.0),c,d,e,f;c=a+b;d=a-b;e=a*b;f=a+1;cout c=;c.Print();cout d=;d.Print();cout e=;e.Print();cout f=;f.Print();第6章 多态性程序运行结果为:程序运行结果为:c=(4,6)c=(4,6)d=(-2,-2)d=(-2,-2)e=(-
14、5,10)e=(-5,10)f=(2,2)f=(2,2)总结:总结:总结:总结:设有双目运算符设有双目运算符设有双目运算符设有双目运算符 B B,如果要重,如果要重,如果要重,如果要重载载载载 B B 为类的成员函数,使之能够实为类的成员函数,使之能够实为类的成员函数,使之能够实为类的成员函数,使之能够实现表达式现表达式现表达式现表达式 oprd1 B oprd2oprd1 B oprd2,其中,其中,其中,其中 oprd1 oprd1 为为为为A A 类对象,则类对象,则类对象,则类对象,则 B B 应被重载应被重载应被重载应被重载为为为为 A A 类的成员函数,形参类型应该类的成员函数,形
15、参类型应该类的成员函数,形参类型应该类的成员函数,形参类型应该是是是是 oprd2 oprd2 所属的类型。所属的类型。所属的类型。所属的类型。经重载后,表达式经重载后,表达式经重载后,表达式经重载后,表达式oprd1 B oprd1 B oprd2 oprd2 相当于相当于相当于相当于 oprd1.operator oprd1.operator B(oprd2)B(oprd2),注意重载双目运算符只,注意重载双目运算符只,注意重载双目运算符只,注意重载双目运算符只需要一个参数。需要一个参数。需要一个参数。需要一个参数。6.2 运算符重载为类的成员函数6.2.2单目运算符重载单目运算符单目运算
16、符,如果,如果重载为类的成员函数重载为类的成员函数,不需要参数不需要参数。为区分前置和后置运算符,为区分前置和后置运算符,C+C+规定:规定:对于对于前置单目运算符前置单目运算符,重载函数,重载函数没有参数没有参数对于对于后置单目运算符后置单目运算符,重载函数,重载函数有一个整型参数有一个整型参数,这个整型参,这个整型参数没有其他用途,只是用于区分前置运算与后置运算。数没有其他用途,只是用于区分前置运算与后置运算。第6章 多态性例例6.36.3定义一个定义一个CIntCInt类,类中只有一个数据成员类,类中只有一个数据成员i i,两个运算,两个运算符符“+”+”的重载函数,一个没有参数,实现的
17、是前置运算符重的重载函数,一个没有参数,实现的是前置运算符重载,另一个有一个整型参数,实现后置运算符重载。载,另一个有一个整型参数,实现后置运算符重载。#includeiostreamusingnamespacestd;classCIntprivate:inti;public:CInt(inta=0);voidPrint();CIntoperator+();CIntoperator+(int);CInt:CInt(inta)CInt:CInt(inta)i=a;i=a;第6章 多态性voidCInt:Print()couti=iendl;CIntCInt:operator+()CInttemp
18、;temp.i=+i;returntemp;CIntCInt:operator+(int)CInttemp;temp.i=i+;returntemp;例例6.36.3(续)(续)voidmain(void)CInta(5),b(5),c,d;c=a+;d=+b;couta:;a.Print();coutb:;b.Print();coutc:;c.Print();coutd:;d.Print();第6章 多态性程序运行结果为:程序运行结果为:a:i=6a:i=6b:i=6b:i=6c:i=5c:i=5d:i=6d:i=66.2 运算符重载为类的成员函数6.2.3赋值运算符重载如果类中只包含简单数
19、据类型的数据成员,则使用如果类中只包含简单数据类型的数据成员,则使用C+C+提供的提供的赋值运算符赋值运算符“=”=”就可以实现将一个对象赋给另一个对象。如前面就可以实现将一个对象赋给另一个对象。如前面复数类的对象,就可以将一个对象直接赋给另一个对象。但如果复数类的对象,就可以将一个对象直接赋给另一个对象。但如果类的数据成员比较复杂(如含有指针),这样直接赋值就会产生类的数据成员比较复杂(如含有指针),这样直接赋值就会产生问题,我们必须重载赋值运算符问题,我们必须重载赋值运算符“=”=”才能正确使用才能正确使用“=”=”。第6章 多态性例例6.46.4类类A A只有一个数据成员只有一个数据成员
20、strstr,是一个字符指针,在构造函,是一个字符指针,在构造函数中为数中为strstr申请存储空间并赋值,在析构函数中释放内存。申请存储空间并赋值,在析构函数中释放内存。#includeiostream#includestringusingnamespacestd;classAprivate:char*str;public:A(char*s=nodata);A();voidprint();A:A(char*s)intlen=strlen(s);str=newcharlen+1;strcpy(str,s);第6章 多态性例例6.46.4(续)(续)A:A()if(str)deletestr;v
21、oidA:print()coutstrendl;voidmain(void)A*p=newA(AAAA);Aa1;a1=*p;a1.print();deletep;a1.print();第6章 多态性strpstra1AAAA该语句只是将该语句只是将p所指向的对象数据成员所指向的对象数据成员str赋给对象赋给对象a1的数据成员的数据成员str,即两个,即两个对象的对象的str指向了同一个单元指向了同一个单元调用析构函数,同时将调用析构函数,同时将str所指向的单元释放了,所指向的单元释放了,再执行再执行a1.print()时,就会出现错误。时,就会出现错误。例例6.56.5带有重载赋值运算符的
22、带有重载赋值运算符的A A类类#includeiostream#includestringusingnamespacestd;classAprivate:char*str;public:A(char*s=nodata);A();A&operator=(A&a);voidprint();A:A(char*s)intlen=strlen(s);str=newcharlen+1;strcpy(str,s);第6章 多态性例6.5(续一)A:A()if(str)deletestr;A&A:operator=(A&a)intlen=strlen(a.str);if(str)deletestr;/先释放,
23、再根据实际需要重新申请str=newcharlen+1;strcpy(str,a.str);return*this;voidA:print()coutstrendl;第6章 多态性例6.5(续二)voidmain(void)A*p=newA(AAAA);Aa1;a1=*p;a1.print();deletep;a1.print();第6章 多态性strpstra1AAAAAAAA程序运行结果为:程序运行结果为:AAAAAAAAAAAAAAAA 返 回6.3 运算符重载为类的友元函数6.3.1问题的提出(1 1)复数与复数相加()复数与复数相加(c1c1,c2c2,c3c3是复数类的对象)。是复
24、数类的对象)。c3=c1+c2c3=c1+c2;(2 2)一个复数与一个实数的加法运算)一个复数与一个实数的加法运算c3=c1+10.8c3=c1+10.8;(3 3)一个实数与一个复数相加就会出现错误。)一个实数与一个复数相加就会出现错误。c3=c3=10.8+c110.8+c1;因为加号左边的运算对象是实数,因为加号左边的运算对象是实数,C+C+试图将加号右边的运算试图将加号右边的运算对象解释为实数,但对象解释为实数,但C+C+无法将一个复数转换为一个实数,从而产无法将一个复数转换为一个实数,从而产生错误。生错误。将运算符重载为友元函数可以解决这个问题。将运算符重载为友元函数可以解决这个问
25、题。第6章 多态性6.3 运算符重载为类的友元函数6.3.2运算符重载为友元函数 类中的类中的声明声明:friendfriend函数类型函数类型 operatoroperator运算符(参数表);运算符(参数表);运算符重载函数的运算符重载函数的定义形式定义形式:函数类型函数类型 operatoroperator运算符(参数表)运算符(参数表)函数体;函数体;第6章 多态性例6.6用友元函数实现复数类加减运算符的重载#includeiostreamusingnamespacestd;classCComplexprivate:doublereal;doubleimag;public:CCompl
26、ex(doubler=0,doublei=0);voidPrint();friendCComplexoperator+(CComplexc1,CComplexc2);friendCComplexoperator-(CComplexc1,CComplexc2);CComplex:CComplex(doubler,doublei)real=r;imag=i;第6章 多态性例6.6(续一)voidCComplex:Print()cout(real,imag)endl;CComplexoperator+(CComplexc1,CComplexc2)CComplextemp;temp.real=c1.r
27、eal+c2.real;temp.imag=c1.imag+c2.imag;returntemp;CComplexoperator-(CComplexc1,CComplexc2)CComplextemp;temp.real=c1.real-c2.real;temp.imag=c1.imag-c2.imag;returntemp;第6章 多态性例6.6(续二)voidmain(void)CComplexa(1,2),b(3.0,4.0),c,d,e;c=a+b;d=b-10;e=20+a;coutc=;c.Print();coutd=;d.Print();coute=;e.Print();第6章
28、 多态性相当于函数调用相当于函数调用“c=operator+(a,b)”程序运行结果为:程序运行结果为:c=c=(4,64,6)d=d=(-7,4-7,4)e=e=(21,221,2)总结:总结:总结:总结:设有双目运算符设有双目运算符设有双目运算符设有双目运算符 B B,如果要重,如果要重,如果要重,如果要重载载载载 B B 为类的友元函数,则该友元函为类的友元函数,则该友元函为类的友元函数,则该友元函为类的友元函数,则该友元函数也有两个参数,分别为运算符的两数也有两个参数,分别为运算符的两数也有两个参数,分别为运算符的两数也有两个参数,分别为运算符的两个运算对象。重载后,表达式个运算对象。
29、重载后,表达式个运算对象。重载后,表达式个运算对象。重载后,表达式oprd1 oprd1 B oprd2 B oprd2 等同于调用函数等同于调用函数等同于调用函数等同于调用函数operator operator B(oprd1,oprd2)B(oprd1,oprd2)。单目运算符也可以重载为类的友单目运算符也可以重载为类的友元函数,该友元函数有一个参数。元函数,该友元函数有一个参数。返 回6.4 虚函数6.4.1用虚函数实现动态多态回顾例回顾例5.65.6voidmain()CShape*ps3;CShapes(Red);CPointp1(10,10),p2(100,100),p3(50,5
30、0);CLinel(p1,p2,Green);CCirclec(p3,20,Black);ps0=&s;ps1=&l;ps2=&c;for(inti=0;iDraw();第6章 多态性程序运行结果为:程序运行结果为:DrawaShape.ThecolorisRedDrawaShape.ThecolorisRedDrawaShape.ThecolorisGreenDrawaShape.ThecolorisGreenDrawaShape.ThecolorisRedBlackDrawaShape.ThecolorisRedBlack虽然父类的指针可以指向子类的对象,但调用虽然父类的指针可以指向子类的
31、对象,但调用的函数的函数Draw()都是父类()都是父类CShape的成员函数的成员函数 为了能通过基类的为了能通过基类的指针调用派生类的成指针调用派生类的成员函数,可以使用虚员函数,可以使用虚函数的方法,即把成函数的方法,即把成员函数员函数Draw()声()声明为虚函数。明为虚函数。例6.7用虚函数实现动态多态#include#include usingnamespacestd;class CPointprivate:int X;int Y;public:CPoint(int x=0,int y=0)X=x;Y=y;CPoint(CPoint&p)X=p.X;Y=p.Y;int GetX()
32、return X;int GetY()return Y;第6章 多态性例6.7(续一)class CShapeprivate:char Color10;public:CShape(char*c)strcpy(Color,c);virtual void Draw()cout Draw a Shape.The color is Color endl;void PrintColor()cout Color endl;第6章 多态性例6.7(续二)class CLine:public CShapeprivate:CPoint Start;CPoint End;public:CLine(CPoint s
33、,CPoint e,char*c):CShape(c),Start(s),End(e)virtual void Draw()cout Draw a Line from(Start.GetX(),Start.GetY();cout )to(End.GetX(),End.GetY(),with color;PrintColor();第6章 多态性例6.7(续三)class CCircle:public CShapeprivate:CPoint Center;int Radius;public:CCircle(CPoint ctr,int r,char*c):CShape(c),Center(ctr
34、)Radius=r;virtual void Draw()cout Draw a Circle at center(Center.GetX(),;cout Center.GetY()with radius Radius and color;PrintColor();第6章 多态性例6.7(续四)void main()CShape*ps3;CShape s(Red);CPoint p1(10,10),p2(100,100),p3(50,50);CLine l(p1,p2,Green);CCircle c(p3,20,Black);ps0=&s;ps1=&l;ps2=&c;for(int i=0;
35、iDraw();第6章 多态性程序运行结果为:程序运行结果为:DrawaShape.ThecolorisRedDrawaShape.ThecolorisRedDrawaLinefrom(10,10)to(100,100),withcolorGreenDrawaLinefrom(10,10)to(100,100),withcolorGreenDrawaCircleatcenter(50,50)withradius20andcolorBlackDrawaCircleatcenter(50,50)withradius20andcolorBlack6.4 虚函数6.4.16.4.1用虚函数实现动态多态
36、(续)用虚函数实现动态多态(续)总结:总结:(1 1)将成员函数声明为)将成员函数声明为虚函数虚函数,在函数原型前加关键字,在函数原型前加关键字virtualvirtual,如果成员函数的定义直接写在类中,也在前面加关键字,如果成员函数的定义直接写在类中,也在前面加关键字virtualvirtual。(2 2)将成员函数声明为虚函数后,再将基类指针指向派生类对)将成员函数声明为虚函数后,再将基类指针指向派生类对象,在程序运行时,就会根据指针指向的具体对象来调用各自的象,在程序运行时,就会根据指针指向的具体对象来调用各自的虚函数,称之为虚函数,称之为动态多态动态多态。(3 3)如果基类的成员函数
37、是虚函数,)如果基类的成员函数是虚函数,在其派生类中,原型相同在其派生类中,原型相同的函数自动成为虚函数的函数自动成为虚函数。第6章 多态性6.4 虚函数6.4.26.4.2用虚函数实现动态多态的机制用虚函数实现动态多态的机制为了实现为了实现动态多态动态多态,编译器对每个包含虚函数的类创建一个,编译器对每个包含虚函数的类创建一个虚虚函数地址函数地址表表表表,并设置一个,并设置一个虚函数地址指针虚函数地址指针指向这个对象的虚函数指向这个对象的虚函数地址表。使用基类指针对虚函数调用时,通过这个虚函数地址指地址表。使用基类指针对虚函数调用时,通过这个虚函数地址指针,在虚函数地址表中查找函数地址。针,
38、在虚函数地址表中查找函数地址。由于由于包含虚函数的类包含虚函数的类,有一个虚函数地址指针,与没有虚函数,有一个虚函数地址指针,与没有虚函数的类相比,含有虚函数类的对象所占用的的类相比,含有虚函数类的对象所占用的存储空间要多一个指针存储空间要多一个指针所占用的内存所占用的内存。第6章 多态性例6.8含有虚函数类的对象所占用的存储空间。#include usingnamespacestd;class Aprivate:int a;public:virtual void func();class B:public A private:int b;public:virtual void func()v
39、irtual void func1();void main(void)void main(void)cout sizeof(A)=sizeof(A)endl;cout sizeof(A)=sizeof(A)endl;cout sizeof(B)=sizeof(B)endl;cout sizeof(B)=sizeof(B)endl;第6章 多态性程序运行结果为:程序运行结果为:sizeof(A)=8sizeof(A)=8sizeof(B)=12sizeof(B)=126.4 虚函数6.4.26.4.2用虚函数实现动态多态的机制(续)用虚函数实现动态多态的机制(续)每个每个含有虚函数类的对象含有虚
40、函数类的对象都有一个都有一个虚函数地址指针虚函数地址指针,指向该类,指向该类虚函数表,如果用基类的指针调用虚函数,在编译时,并不能确虚函数表,如果用基类的指针调用虚函数,在编译时,并不能确定这个指针的具体指向,而是在运行时,定这个指针的具体指向,而是在运行时,根据指针所指向的具体根据指针所指向的具体对象对象(基类的对象或其派生类的对象),(基类的对象或其派生类的对象),虚函数地址指针才有一虚函数地址指针才有一个确定的值个确定的值,即相应类的这个虚函数的地址。从而实现动态多态。,即相应类的这个虚函数的地址。从而实现动态多态。第6章 多态性6.4 虚函数6.4.36.4.3虚析构函数虚析构函数析构
41、函数也可以定义为虚函数,如果基类的析构函数定义为虚析构函数也可以定义为虚函数,如果基类的析构函数定义为虚析构函数,则派生类的析构函数就会自动成为虚析构函数。析构函数,则派生类的析构函数就会自动成为虚析构函数。如果如果基类的指针指向派生类对象基类的指针指向派生类对象,当用,当用deletedelete删除这个对象时,删除这个对象时,若析构函数不是虚函数,就要若析构函数不是虚函数,就要调用基类的析构函数调用基类的析构函数,而,而不会调用不会调用派生类的析构函数派生类的析构函数。如果为基类和派生类的对象分配了动态内存,。如果为基类和派生类的对象分配了动态内存,或者为派生类的对象成员分配了动态内存,这
42、时释放的只是基类或者为派生类的对象成员分配了动态内存,这时释放的只是基类中动态分配的内存,而派生类中动态分配的内存未被释放,因此中动态分配的内存,而派生类中动态分配的内存未被释放,因此一般应将析构函数定义为虚析构函数一般应将析构函数定义为虚析构函数。第6章 多态性例例6.96.9定义职员类定义职员类CEmployeeCEmployee,数据成员有姓名(字符指针,数据成员有姓名(字符指针型数据)和年龄,由型数据)和年龄,由CEmployeeCEmployee类派生出教师类类派生出教师类CTeacherCTeacher,增加数据成员教学简历(字符指针型数据)。增加数据成员教学简历(字符指针型数据)
43、。#include#include usingnamespacestd;class CEmployeeprivate:char*name;int age;public:CEmployee(char*n,int a);virtual CEmployee();CEmployee:CEmployee(char*n,int a)name=new charstrlen(n)+1;strcpy(name,n);age=a;第6章 多态性例例6.96.9(续一)(续一)CEmployee:CEmployee()cout Destruct CEmployee endl;if(name)delete name;
44、class CTeacher:public CEmployee class CTeacher:public CEmployee private:private:char*mainCourse;char*mainCourse;public:public:CTeacher(char*n,char*course,int a);CTeacher(char*n,char*course,int a);virtual CTeacher();virtual CTeacher();/由于基类已定义虚析构函数,此处也可不加由于基类已定义虚析构函数,此处也可不加由于基类已定义虚析构函数,此处也可不加由于基类已定义虚
45、析构函数,此处也可不加virtualvirtual;CTeacher:CTeacher(char*n,char*course,int a):CEmployee(n,a)CTeacher:CTeacher(char*n,char*course,int a):CEmployee(n,a)mainCourse=new charstrlen(course)+1;mainCourse=new charstrlen(course)+1;strcpy(mainCourse,course);strcpy(mainCourse,course);第6章 多态性例例6.96.9(续二)(续二)CTeacher:CT
46、eacher()cout Destruct CTeacher endl;if(mainCourse)delete mainCourse;void main(void)CEmployee*p3;p0=new CEmployee(Name1,20);p1=new CTeacher(Name2,C for 2 years,C+3 years,26);p2=new CTeacher(Name3,Data structure for 2 years,C+3 years,30);for(int i=0;i3;i+)delete pi;第6章 多态性程序运行结果为:程序运行结果为:DestructCEmpl
47、oyeeDestructCEmployeeDestructCTeacherDestructCTeacherDestructCEmployeeDestructCEmployeeDestructCTeacherDestructCTeacherDestructCEmployeeDestructCEmployee若不定义为虚析构函数,程序运行结果为:若不定义为虚析构函数,程序运行结果为:DestructCEmployeeDestructCEmployeeDestructCEmployeeDestructCEmployeeDestructCEmployeeDestructCEmployee由于未调用由于
48、未调用CTeacher类析构类析构函数,导致成员函数,导致成员mainCourse空间未被释放空间未被释放6.4 虚函数6.4.46.4.4纯虚函数与抽象类纯虚函数与抽象类 纯虚函数纯虚函数是不必定义函数体的特殊虚函数,纯虚函数的声明是不必定义函数体的特殊虚函数,纯虚函数的声明格式为:格式为:virtualvirtual函数类型函数类型 函数名(参数表)函数名(参数表)=0=0;含有含有纯虚函数纯虚函数的类称为的类称为抽象类抽象类。抽象类常常用作派生类的基。抽象类常常用作派生类的基类。类。如果派生类继承了抽象类的纯虚函数,却没有重新定义原型相如果派生类继承了抽象类的纯虚函数,却没有重新定义原型
49、相同且带函数体的虚函数,或者派生类定义了基类所没有定义的纯同且带函数体的虚函数,或者派生类定义了基类所没有定义的纯虚函数,则派生类仍然是抽象类,在多层派生的过程中,如果到虚函数,则派生类仍然是抽象类,在多层派生的过程中,如果到某个派生类为止,某个派生类为止,所有纯虚函数都已全部重新定义,则该派生类所有纯虚函数都已全部重新定义,则该派生类就成为非抽象类就成为非抽象类。不能定义抽象类的对象,但可以声明抽象类的指针和引用不能定义抽象类的对象,但可以声明抽象类的指针和引用。第6章 多态性例例6.106.10将例题将例题6.76.7中中CShapeCShape类的函数类的函数DrawDraw()声明为纯
50、虚()声明为纯虚函数,其它类保持不变。函数,其它类保持不变。class CShapeprivate:char Color10;public:CShape(char*c)strcpy(Color,c);virtual void Draw()0;void PrintColor()cout Color endl;第6章 多态性void main()CShape*ps3;CPoint p1(10,10),p2(100,100),p3(50,50);CLine l(p1,p2,Green);CCircle c(p3,20,Black);ps1=&l;ps2=&c;for(int i=1;iDraw();