《第8章多态性1》由会员分享,可在线阅读,更多相关《第8章多态性1(48页珍藏版)》请在金锄头文库上搜索。
1、第8章多态性8.1运算符重载8.2运算符重载为类的成员函数8.3运算符重载为类的友元函数8.4虚函数8.1 运算符重载8.1.1问题的提出例例6.36.3的复数类的复数类#include #include iostream.hiostream.h class class CComplexCComplex private:private:double real;double real;double double imagimag; ;public:public:CComplex(doubleCComplex(double r, double i); r, double i);void Print
2、();void Print();CComplexCComplex Add(CComplexAdd(CComplex c); c);CComplexCComplex Sub(CComplexSub(CComplex c); c); ;第8章 多态性CComplex CComplex:Add(CComplex c)CComplex temp;temp.real = real + c.real;temp.imag = imag + c.imag;return temp;CComplex CComplex:Sub(CComplex c)CComplex temp;temp.real = real -
3、c.real;temp.imag = imag - c.imag;return temp;8.1 运算符重载8.1.1问题的提出(续一)void void main(voidmain(void) ) CComplexCComplex a(1, 2), b(3.0, 4.0), a(1, 2), b(3.0, 4.0), c,dc,d; ;c = c = a.Add(ba.Add(b); );d = d = a.Sub(ba.Sub(b); );coutcout c = ; c = ;c.Printc.Print();();coutcout d = ; d = ;d.Printd.Print()
4、;(); 第8章 多态性复数加减法只能调用成员函数实现,复数加减法只能调用成员函数实现,不能使用符号不能使用符号“+”和和“-”,可以通,可以通过重载过重载“+”、“-”运算符,实现如运算符,实现如c=a+b这样的调用方式这样的调用方式运算符重载:运算符重载的实质就是对已有的运算符赋予多重含义,使同一个运算符运算符重载:运算符重载的实质就是对已有的运算符赋予多重含义,使同一个运算符作用于不同类型的数据时,产生不同的行为。运算符重载的实质就是函数重载。作用于不同类型的数据时,产生不同的行为。运算符重载的实质就是函数重载。 例例8.18.1用运算符实现复数的加减运算用运算符实现复数的加减运算#in
5、cludeiostream.hclassCComplexprivate:doublereal;doubleimag;public:CComplex(doubler=0,doublei=0);voidPrint();CComplexoperator+(CComplexc);CComplexoperator-(CComplexc);CComplex:CComplex(doubler,doublei)real=r;imag=i; 第8章 多态性例例8.18.1(续一)(续一)voidCComplex:Print()cout(real,imag)endl;CComplexCComplex:operat
6、or+(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; 第8章 多态性例例8.18.1(续二)(续二)voidmain(void)CComplexa(1,2),b(3.0,4.0),c,d;c=a+b;d=a-b;coutc=;c.Print();coutd=;d.Print()
7、; 第8章 多态性该语句相当于对函数该语句相当于对函数operator +(CComplex c)的调用:的调用:“c=a.operator +(b)”,实现两个复数,实现两个复数的加法运算。的加法运算。程序运行结果为:程序运行结果为:c=(4,6)c=(4,6)d=(-2,-2)d=(-2,-2)8.1 运算符重载8.1.2运算符重载的格式与规则1.1.运算符重载的格式运算符重载的格式运算符重载的格式运算符重载的格式 运算符重载为类的成员函数运算符重载为类的成员函数 运算符重载为类的友元函数运算符重载为类的友元函数 运算符重载的为类的成员函数,在类中声明的格式为:运算符重载的为类的成员函数,
8、在类中声明的格式为:运算符重载的为类的成员函数,在类中声明的格式为:运算符重载的为类的成员函数,在类中声明的格式为:函数类型函数类型 operatoroperator运算符(参数表);运算符(参数表);定义该函数的格式:定义该函数的格式:定义该函数的格式:定义该函数的格式:函数类型函数类型 类名类名:operator:operator运算符(参数表)运算符(参数表) 函数体;函数体; 也可以将重载运算符函数的定义直接写在类中。也可以将重载运算符函数的定义直接写在类中。第8章 多态性8.1 运算符重载8.1.2运算符重载的格式与规则(续)2.2.运算符重载的规则运算符重载的规则运算符重载的规则运
9、算符重载的规则(1 1)除)除“ “.” .”、“*”“*”、“ “:”:”、“ “?:”?:”和和“ “sizeofsizeof” ”等几个运等几个运算符不能重载外,算符不能重载外,C+C+中几乎所有的运算符都可以重载。中几乎所有的运算符都可以重载。(2 2)运算符被重载后,其优先级和结合性不会改变。)运算符被重载后,其优先级和结合性不会改变。(3 3)不能改变运算符操作对象的个数。)不能改变运算符操作对象的个数。第8章 多态性 返 回8.2 运算符重载为类的成员函数8.2.1双目运算符重载双目运算符双目运算符,如果,如果重载为类的成员函数重载为类的成员函数,其,其参数为一个参数为一个,即比
10、,即比运算对象少一个。运算对象少一个。例例8.28.2复数的乘法运算,在上例的基础上添加乘法运算符重复数的乘法运算,在上例的基础上添加乘法运算符重载函数。复数类乘法运算的定义如下:载函数。复数类乘法运算的定义如下:(a+bia+bi)* *(x+yix+yi)=a*=a*x-bx-b*y+(a*y+b*y+(a*y+b*x)ix)i第8章 多态性例例8.28.2复数乘法运算源程序复数乘法运算源程序#includeiostream.hclassCComplexprivate:doublereal;doubleimag;public:CComplex(doubler=0,doublei=0);vo
11、idPrint();CComplexoperator+(CComplexc);CComplexoperator-(CComplexc);CComplexoperator*(CComplexc); CComplex:CComplexCComplex:CComplex(doubler,doublei)(doubler,doublei) real=r;real=r;imagimag=i;=i; 第8章 多态性例例8.28.2(续一)(续一)voidCComplex:Print()cout(real,imag)endl;CComplexCComplex:operator+(CComplexc)CCom
12、plextemp;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; 第8章 多态性例例8.28.2(续二)(续二)CComplex CComplex:operator *(CComplex c)CComplex temp;temp.real = real * c.real - imag * c.imag;temp.imag =
13、 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();第8章 多态性程序运行结果为:程序运行结果为:c=(4,6)c=(4,6)d=(-2,-2)d=(-2,-2)e=(-5,10)e=(-5,10)f=(2,2)f=(2,2)
14、总结:总结:总结:总结:设有双目运算符设有双目运算符设有双目运算符设有双目运算符 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),注意重载双目运算符只,注意重载双目运算符只,注意重载双目运算符只,注意重载双目运算符只需要一个参数。需要一个参数。需要一个参数。需要一个参数。8.2 运算符重载为类的成员函数8.2.2单目运算符重载单目运算符单目运算符,如果,如果重载为类的成员函数重载为类的成员函数,不
16、需要参数不需要参数。为区分前置和后置运算符,为区分前置和后置运算符,C+C+规定:规定:对于对于前置单目运算符前置单目运算符,重载函数,重载函数没有参数没有参数对于对于后置单目运算符后置单目运算符,重载函数,重载函数有一个整型参数有一个整型参数,这个整型参,这个整型参数没有其他用途,只是用于区分前置运算与后置运算。数没有其他用途,只是用于区分前置运算与后置运算。第8章 多态性例例8.38.3定义一个定义一个CIntCInt类,类中只有一个数据成员类,类中只有一个数据成员i i,两个运算,两个运算符符“ “+”+”的重载函数,一个没有参数,实现的是前置运算符重的重载函数,一个没有参数,实现的是前
17、置运算符重载,另一个有一个整型参数,实现后置运算符重载。载,另一个有一个整型参数,实现后置运算符重载。#includeiostream.hclassCIntprivate:inti;public:CInt(inta=0);voidPrint();CIntoperator+();CIntoperator+(int); CInt:CIntCInt:CInt( (intinta)a) i=a;i=a; 第8章 多态性voidCInt:Print()couti=iendl;CIntCInt:operator+()CInttemp;temp.i=+i;returntemp;CIntCInt:operat
18、or+(int)CInttemp;temp.i=i+;returntemp; 例例8.38.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(); 第8章 多态性程序运行结果为:程序运行结果为:a:i=6a:i=6b:i=6b:i=6c:i=5c:i=5d:i=6d:i=68.2 运算符重载为类的成员函数8.2.3赋值运算符重载如果类中只包含简单数据类型的数据成员,则使用如果类中只包含简单数据类型的数据成员,则使用C
19、+C+提供的提供的赋值运算符赋值运算符“ “=”=”就可以实现将一个对象赋给另一个对象。如前面就可以实现将一个对象赋给另一个对象。如前面复数类的对象,就可以将一个对象直接赋给另一个对象。但如果复数类的对象,就可以将一个对象直接赋给另一个对象。但如果类的数据成员比较复杂(如含有指针),这样直接赋值就会产生类的数据成员比较复杂(如含有指针),这样直接赋值就会产生问题,我们必须重载赋值运算符问题,我们必须重载赋值运算符“ “=”=”才能正确使用才能正确使用“ “=”=”。第8章 多态性例例8.48.4类类A A只有一个数据成员只有一个数据成员strstr,是一个字符指针,在构造函,是一个字符指针,在
20、构造函数中为数中为strstr申请存储空间并赋值,在析构函数中释放内存。申请存储空间并赋值,在析构函数中释放内存。#includeiostream.h#includestring.hclassAprivate:char*str;public:A(char*s=nodata);A();voidprint();A:A(char*s)intlen=strlen(s);str=newcharlen+1;strcpy(str,s); 第8章 多态性例例8.48.4(续)(续)A:A()if(str)deletestr;voidA:print()coutstrendl;voidmain(void)A*p=
21、newA(AAAA);Aa1;a1=*p;a1.print();deletep;a1.print(); 第8章 多态性strpstra1AAAA该语句只是将该语句只是将p所指向的对象数据成员所指向的对象数据成员str赋给对象赋给对象a1的数据成员的数据成员str,即两个,即两个对象的对象的str指向了同一个单元指向了同一个单元调用析构函数,同时将调用析构函数,同时将str所指向的单元释放了,所指向的单元释放了,再执行再执行a1.print()时,就会出现错误。时,就会出现错误。例例8.58.5带有重载赋值运算符的带有重载赋值运算符的A A类类#includeiostream.h#include
22、string.hclassAprivate: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); 第8章 多态性例8.5(续一)A:A()if(str)deletestr;A&A:operator=(A&a)intlen=strlen(a.str);if(str)deletestr;/先释放,再根据实际需要重新申请str=newcharlen+1;strcpy(str,a.str);return*
23、this;voidA:print()coutstrendl; 第8章 多态性例8.5(续二)voidmain(void)A*p=newA(AAAA);Aa1;a1=*p;a1.print();deletep;a1.print(); 第8章 多态性strpstra1AAAAAAAA程序运行结果为:程序运行结果为:AAAAAAAAAAAAAAAA 返 回8.3 运算符重载为类的友元函数8.3.1问题的提出(1 1)复数与复数相加()复数与复数相加(c1c1,c2c2,c3c3是复数类的对象)。是复数类的对象)。c3=c1+c2c3=c1+c2;(2 2)一个复数与一个实数的加法运算)一个复数与一个
24、实数的加法运算c3=c1+10.8c3=c1+10.8;(3 3)一个实数与一个复数相加就会出现错误。)一个实数与一个复数相加就会出现错误。c3=c3=10.8 + c110.8 + c1;因为加号左边的运算对象是实数,因为加号左边的运算对象是实数,C+C+试图将加号右边的运算试图将加号右边的运算对象解释为实数,但对象解释为实数,但C+C+无法将一个复数转换为一个实数,从而产无法将一个复数转换为一个实数,从而产生错误。生错误。将运算符重载为友元函数可以解决这个问题。将运算符重载为友元函数可以解决这个问题。第8章 多态性8.3 运算符重载为类的友元函数8.3.2运算符重载为友元函数 类中的类中的
25、声明声明: friendfriend函数类型函数类型 operatoroperator运算符(参数表);运算符(参数表);运算符重载函数的运算符重载函数的定义形式定义形式: 函数类型函数类型 operatoroperator运算符(参数表)运算符(参数表)函数体;函数体;第8章 多态性例8.6用友元函数实现复数类加减运算符的重载#includeiostream.hclassCComplexprivate:doublereal;doubleimag;public:CComplex(doubler=0,doublei=0);voidPrint();friendCComplexoperator+(C
26、Complexc1,CComplexc2);friendCComplexoperator-(CComplexc1,CComplexc2);CComplex:CComplex(doubler,doublei)real=r;imag=i; 第8章 多态性例8.6(续一)voidCComplex:Print()cout(real,imag)endl;CComplexoperator+(CComplexc1,CComplexc2)CComplextemp;temp.real=c1.real+c2.real;temp.imag=c1.imag+c2.imag;returntemp;CComplexope
27、rator-(CComplexc1,CComplexc2)CComplextemp;temp.real=c1.real-c2.real;temp.imag=c1.imag-c2.imag;returntemp; 第8章 多态性例8.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();cout”和插入运算符“”可用来输入输出标准类型的数据。这两个运算符是C+编译器在类库中提供的。我们可以重载这两个运算符以便输入输出用户自定义类型的数据。例1
28、.重载插入运算符“”以处理用户自定义类complex的数据。#include#include #include#include usingnamespacestd;usingnamespacestd;ClasscomplexClasscomplexprivate:private:doubledoublex,yx,y; ;public:public:Complex(doubleComplex(doublexx=0;doublexx=0;doubleyyyy=0)=0)x=x=xx;yxx;y= =yyyy; ;cin是C+输入流istream预定义对象,代表标准输入设备键盘;cout是C+输出流
29、ostream预定义对象,代表标准输出设备显示器。friendfriendostreamostream&operator(&operator(ostreamostream&,constcomplex&);/&,constcomplex&);/声明重载运声明重载运算符算符(&operator(istreamistream&,complex&);/&,complex&);/声明重载运算符声明重载运算符; ;ostreamostream&operator(&operator(ostreamostream&output,constoutput,constcomplex&c)complex&c)outp
30、ut“(“output“(“0)0)output“+”output“+”c.yc.y“*i“*i)” ”; ;elseelseif(c.yif(c.y0)0)outputoutputc.yc.y“*i)”;“*i)”;elseelseoutput“)”;output中有两个参数,一个是istream流的引用,另一个是用户自定义类complex的引用。istreamistream&operator(&operator(istreamistream&input,complex&input,complex&c)c)coutcout“inputc.xc.x; ;coutcout“inputc.yc.y
31、; ;returninput;returninput; intintmain()main()complexc;complexc;coutcout“输入复数输入复数c:”c:”c;c;coutcout“c=“c“c=“c”、“”,实现Date类对象的输入和输出。8.4 虚函数8.4.1用虚函数实现动态多态回顾例回顾例7.67.6voidmain()CShape*ps3;CShapes(Red);CPointp1(10,10),p2(100,100),p3(50,50);CLinel(p1,p2,Green);CCirclec(p3,20,Black);ps0=&s;ps1=&l;ps2=&c;f
32、or(inti=0;iDraw(); 第8章 多态性程序运行结果为:程序运行结果为:DrawaShape.ThecolorisRedDrawaShape.ThecolorisRedDrawaShape.ThecolorisGreenDrawaShape.ThecolorisGreenDrawaShape.ThecolorisRedBlackDrawaShape.ThecolorisRedBlack虽然父类的指针可以指向子类的对象,但调用虽然父类的指针可以指向子类的对象,但调用的函数的函数Draw()都是父类()都是父类CShape的成员函数的成员函数 为了能通过基类的为了能通过基类的指针调用派
33、生类的成指针调用派生类的成员函数,可以使用虚员函数,可以使用虚函数的方法,即把成函数的方法,即把成员函数员函数Draw()声()声明为虚函数。明为虚函数。例8.7用虚函数实现动态多态#include #include 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() return X;int GetY() return Y;第8章 多态性例8.7(续一)class CShapeprivate:char Color10
34、;public:CShape(char *c)strcpy(Color,c);virtual void Draw()cout Draw a Shape. The color is Color endl;void PrintColor()cout Color endl;第8章 多态性例8.7(续二)class CLine:public CShapeprivate:CPoint Start;CPoint End;public:CLine(CPoint s, CPoint e, char *c):CShape(c),Start(s),End(e)virtual void Draw()cout Dra
35、w a Line from ( Start.GetX() , Start.GetY();cout ) to ( End.GetX() , End.GetY() ), with color ;PrintColor(); 第8章 多态性例8.7(续三)class CCircle:public CShapeprivate:CPoint Center;int Radius;public:CCircle(CPoint ctr, int r, char *c):CShape(c),Center(ctr)Radius = r;virtual void Draw()cout Draw a Circle at
36、center ( Center.GetX() , ;cout Center.GetY() ) with radius Radius and color ;PrintColor(); 第8章 多态性例8.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; iDraw(); 第8章 多态性程序运行结果为:程序运行结果为
37、:DrawaShape.ThecolorisRedDrawaShape.ThecolorisRedDrawaLinefrom(10,10)to(100,100),withcolorGreenDrawaLinefrom(10,10)to(100,100),withcolorGreenDrawaCircleatcenter(50,50)withradius20andcolorBlackDrawaCircleatcenter(50,50)withradius20andcolorBlack8.4 虚函数8.4.18.4.1用虚函数实现动态多态(续)用虚函数实现动态多态(续)总结:总结: (1 1)将成
38、员函数声明为)将成员函数声明为虚函数虚函数,在函数原型前加关键字,在函数原型前加关键字virtualvirtual,如果成员函数的定义直接写在类中,也在前面加关键字,如果成员函数的定义直接写在类中,也在前面加关键字virtualvirtual。(2 2)将成员函数声明为虚函数后,再将基类指针指向派生类对)将成员函数声明为虚函数后,再将基类指针指向派生类对象,在程序运行时,就会根据指针指向的具体对象来调用各自的象,在程序运行时,就会根据指针指向的具体对象来调用各自的虚函数,称之为虚函数,称之为动态多态动态多态。(3 3)如果基类的成员函数是虚函数,)如果基类的成员函数是虚函数,在其派生类中,原型
39、相同在其派生类中,原型相同的函数自动成为虚函数的函数自动成为虚函数。第8章 多态性8.4 虚函数8.4.28.4.2用虚函数实现动态多态的机制用虚函数实现动态多态的机制为了实现为了实现动态多态动态多态,编译器对每个包含虚函数的类创建一个,编译器对每个包含虚函数的类创建一个虚虚函数地址函数地址表表表表,并设置一个,并设置一个虚函数地址指针虚函数地址指针指向这个对象的虚函数指向这个对象的虚函数地址表。使用基类指针对虚函数调用时,通过这个虚函数地址指地址表。使用基类指针对虚函数调用时,通过这个虚函数地址指针,在虚函数地址表中查找函数地址。针,在虚函数地址表中查找函数地址。由于由于包含虚函数的类包含虚
40、函数的类,有一个虚函数地址指针,与没有虚函数,有一个虚函数地址指针,与没有虚函数的类相比,含有虚函数类的对象所占用的的类相比,含有虚函数类的对象所占用的存储空间要多一个指针存储空间要多一个指针所占用的内存所占用的内存。 第8章 多态性例8.8含有虚函数类的对象所占用的存储空间。#include class Aprivate:int a;public:virtual void func();class B : public A private:int b;public:virtual void func() virtual void func1() ; void void main(voidma
41、in(void) ) coutcout sizeof(Asizeof(A)= )= sizeof(Asizeof(A) ) endlendl; ;coutcout sizeof(Bsizeof(B)= )= sizeof(Bsizeof(B) ) endlendl; ; 第8章 多态性程序运行结果为:程序运行结果为:sizeof(Asizeof(A)=8)=8sizeof(Bsizeof(B)=12)=128.4 虚函数8.4.28.4.2用虚函数实现动态多态的机制(续)用虚函数实现动态多态的机制(续)每个每个含有虚函数类的对象含有虚函数类的对象都有一个都有一个虚函数地址指针虚函数地址指针,指
42、向该类,指向该类虚函数表,如果用基类的指针调用虚函数,在编译时,并不能确虚函数表,如果用基类的指针调用虚函数,在编译时,并不能确定这个指针的具体指向,而是在运行时,定这个指针的具体指向,而是在运行时,根据指针所指向的具体根据指针所指向的具体对象对象(基类的对象或其派生类的对象),(基类的对象或其派生类的对象),虚函数地址指针才有一虚函数地址指针才有一个确定的值个确定的值,即相应类的这个虚函数的地址。从而实现动态多态。,即相应类的这个虚函数的地址。从而实现动态多态。 第8章 多态性8.4 虚函数8.4.38.4.3虚析构函数虚析构函数析构函数也可以定义为虚函数,如果基类的析构函数定义为虚析构函数
43、也可以定义为虚函数,如果基类的析构函数定义为虚析构函数,则派生类的析构函数就会自动成为虚析构函数。析构函数,则派生类的析构函数就会自动成为虚析构函数。如果如果基类的指针指向派生类对象基类的指针指向派生类对象,当用,当用deletedelete删除这个对象时,删除这个对象时,若析构函数不是虚函数,就要若析构函数不是虚函数,就要调用基类的析构函数调用基类的析构函数,而,而不会调用不会调用派生类的析构函数派生类的析构函数。如果为基类和派生类的对象分配了动态内存,。如果为基类和派生类的对象分配了动态内存,或者为派生类的对象成员分配了动态内存,这时释放的只是基类或者为派生类的对象成员分配了动态内存,这时
44、释放的只是基类中动态分配的内存,而派生类中动态分配的内存未被释放,因此中动态分配的内存,而派生类中动态分配的内存未被释放,因此一般应将析构函数定义为虚析构函数一般应将析构函数定义为虚析构函数。 第8章 多态性例例8.98.9定义职员类定义职员类CEmployeeCEmployee,数据成员有姓名(字符指针,数据成员有姓名(字符指针型数据)和年龄,由型数据)和年龄,由CEmployeeCEmployee类派生出教师类类派生出教师类CTeacherCTeacher,增加数据成员教学简历(字符指针型数据)。增加数据成员教学简历(字符指针型数据)。 #include #include class CE
45、mployeeprivate: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; 第8章 多态性例例8.98.9(续一)(续一) CEmployee:CEmployee() cout Destruct CEmployee endl;if(name) delete name; class class CTeacherCTeache
46、r : public : public CEmployeeCEmployee private:private:char *char *mainCoursemainCourse; ;public:public:CTeacher(charCTeacher(char *n, char *course, *n, char *course, intint a); a);virtual virtual CTeacherCTeacher();(); / /由于基类已定义虚析构函数,此处也可不加由于基类已定义虚析构函数,此处也可不加由于基类已定义虚析构函数,此处也可不加由于基类已定义虚析构函数,此处也可不加v
47、irtualvirtual; ;CTeacher:CTeacher(charCTeacher:CTeacher(char *n, char * course, *n, char * course, intint a) : a) : CEmployee(n,aCEmployee(n,a) ) mainCoursemainCourse = new charstrlen(course)+1; = new charstrlen(course)+1;strcpy(mainCoursestrcpy(mainCourse, course);, course); 第8章 多态性例例8.98.9(续二)(续二)
48、 CTeacher:CTeacher() 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; 第8章 多态性
49、程序运行结果为:程序运行结果为:DestructDestructCEmployeeCEmployeeDestructDestructCTeacherCTeacherDestructDestructCEmployeeCEmployeeDestructDestructCTeacherCTeacherDestructDestructCEmployeeCEmployee若不定义为虚析构函数,程序运行结果为:若不定义为虚析构函数,程序运行结果为:DestructDestructCEmployeeCEmployeeDestructDestructCEmployeeCEmployeeDestructDest
50、ructCEmployeeCEmployee由于未调用由于未调用CTeacher类析构类析构函数,导致成员函数,导致成员mainCourse空间未被释放空间未被释放8.4 虚函数8.4.48.4.4纯虚函数与抽象类纯虚函数与抽象类 纯虚函数纯虚函数是不必定义函数体的特殊虚函数,纯虚函数的声明是不必定义函数体的特殊虚函数,纯虚函数的声明格式为:格式为: virtualvirtual函数类型函数类型 函数名(参数表)函数名(参数表)=0=0; 含有含有纯虚函数纯虚函数的类称为的类称为抽象类抽象类。抽象类常常用作派生类的基。抽象类常常用作派生类的基类。类。如果派生类继承了抽象类的纯虚函数,却没有重新
51、定义原型相如果派生类继承了抽象类的纯虚函数,却没有重新定义原型相同且带函数体的虚函数,或者派生类定义了基类所没有定义的纯同且带函数体的虚函数,或者派生类定义了基类所没有定义的纯虚函数,则派生类仍然是抽象类,在多层派生的过程中,如果到虚函数,则派生类仍然是抽象类,在多层派生的过程中,如果到某个派生类为止,某个派生类为止,所有纯虚函数都已全部重新定义,则该派生类所有纯虚函数都已全部重新定义,则该派生类就成为非抽象类就成为非抽象类。不能定义抽象类的对象,但可以声明抽象类的指针和引用不能定义抽象类的对象,但可以声明抽象类的指针和引用。第8章 多态性例例8.108.10将例题将例题8.78.7中中CSh
52、apeCShape类的函数类的函数DrawDraw()声明为纯虚()声明为纯虚函数,其它类保持不变。函数,其它类保持不变。class CShapeprivate:char Color10;public:CShape(char *c)strcpy(Color,c);virtual void Draw()0;void PrintColor()cout Color endl; 第8章 多态性void main()CShape *ps3;CPoint p1(10,10), p2(100,100),p3(50,50);CLine l(p1,p2,Green);CCircle c(p3, 20, Blac
53、k);ps1 = &l;ps2 = &c;for(int i=1; iDraw();程序运行结果为:程序运行结果为:DrawaLinefrom(10,10)to(100,100),withcolorGreenDrawaLinefrom(10,10)to(100,100),withcolorGreenDrawaCircleatcenter(50,50)withradius20andcolorBlackDrawaCircleatcenter(50,50)withradius20andcolorBlack不能定义不能定义CShape类的对象,类的对象,但可以定义但可以定义CShape类的指针类的指针 返 回谢谢!