《《多态性和虚函数》PPT课件.ppt》由会员分享,可在线阅读,更多相关《《多态性和虚函数》PPT课件.ppt(141页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、多态性和虚函数多态性和虚函数 l封装性是基础,继承性是关键,多态性是补充封装性是基础,继承性是关键,多态性是补充l多态性是指发出同样的消息被不同类型的对象接收多态性是指发出同样的消息被不同类型的对象接收时导致完全不同的行为:时导致完全不同的行为:函数和运算符重载函数和运算符重载 虚函数、虚函数、动态联编动态联编1 函数重载函数重载l函数重载就是赋给同一个函数名多个含义lC中允许在相同的作用域内以相同的名字定义几个不同实现的函数,可以使成员函数,也可以是非成员函数l要求函数的参数或者至少有一个类型不同,或者个数不同l参数个数和类型都相同,仅仅返回值不同的重载函数是非法的例例 构造函数进行重载#i
2、nclude#includeclassstringpublic:string(char*s);string(string&s1);string(intsize=80);string()deletesptr;intgetlen()returnlength;voidprint()coutsptrendl;private:char*sptr;intlength;string:string(char*s)length=strlen(s);sptr=newcharlength+1;strcpy(sptr,s);string:string(string&s1)length=s1.length;sptr=n
3、ewcharlength+1;strcpy(sptr,s1.sptr);string:string(intsize)length=size;sptr=newcharlength+1;*sptr=0;voidmain()stringstr1(Thisisastring.);str1.print();coutstr1.getlen()endl;char*s1=Thatisaprogram.;stringstr2(s1);stringstr3(str2);str3.print();coutstr3.getlen()endl;Ans:Thisisastring.17Thatisaprogram.18函
4、数重载应注意问题:l不要使用重载函数来描述毫无相干的函数l构造函数可以重载,普通成员函数也可以重载l在重载函数中使用缺省函数参数时应注意调用的二义性,例如:voidprint(inta,intb)couta=a,b=bendl;voidprint(inta,intb,intc=50)couta=a,b=bendl;下列函数调用,由于二义性将通不过:print(10,100);2 运算符重载运算符重载l运算符重载就是赋予已有的运算符多重含义lC中通过重新定义运算符,使它能够用于特定类的对象执行特定的功能l增强了C语言的扩充能力2.1 运算符重载的概念 l为了介绍运算符重载的概念,先看一个运算符重
5、载的引例。引例:用“+”运算符完成两个实数、两个复数、两个字符串的相关运算。(1)实数设有两个实数:x1=10,x2=20,则两个实数相加的结果是:x1+x2=10+20=30。(2)复数设有两个复数:x1=10+10i,x2=20+20i,则两复数相加结果是:x1+x2=30+30i。(3)字符串设有两个字符串:x1=“ABCD”,x2=“EFGH”,则两字符串连接的结果:x1+x2=ABCDEFGH2.1 运算符重载的概念由上例可以看出,同一个运算符“+”可用于完成实数加法、复数加法及字符串连接等不同的运算,得到完全不同的结果。这就是“+”运算符的重载。因此,所谓运算符重载就是用同一个运算
6、符完成不同的运算操作。在C+这类面向对象的程序设计语言中,运算符重载可以完成两个对象的复杂操作(如:两个复数的算术运算等)。而运算符重载是通过运算符重载函数来完成的。当编译器遇到重载运算符,如复数加法:x1+x2中的加号运算符“+”时,自动调用“+”运算符的重载函数完成两个复数对象的加法操作。由于二元运算符的重载函数与一元运算符的重载函数有较大区别,因此分开介绍。先介绍二元运算符重载函数,再介绍一元运算符重载函数。2.2 二元运算符重载函数 l运算符重载函数可以是类的成员函数或者是友元函数。2.2 二元运算符重载函数l1运算符重载函数为类的成员函数运算符重载函数为类的成员函数一般定义格式为::
7、(形参表)函数体其中,类型为运算符重载函数的返回类型。类名为成员函数所属类的类名。关键词“operator”加上“重载运算符”为重载函数名,即:重载函数名=operator重载运算符。形参常为参加运算的对象或数据。2.2 二元运算符重载函数l例定义一个复数类,重载“=”运算符,使这个运算符能直接完成复数的赋值运算。#includeclassComplexprivate:floatReal,Image;public:Complex(floatr=0,floati=0)Real=r;Image=i;/缺省构造函数voidShow(inti)/显示输出复数coutci=Real+Imageiendl
8、;voidoperator=(Complex&c)/“=”运算符重载函数完成复数赋值操作Real=c.Real;Image=c.Image;voidmain(void)Complexc1(25,50),c2;c1.Show(1);c2=c1;c2.Show(2);程序执行后输出:c1=25+50ic2=25+50i在程序中,定义了一个赋值运算符“=”的重载函数:voidoperator=(Complex&c)Real=c.Real;Image=c.Image;2.2 二元运算符重载函数l该重载函数的函数名为“operator=”,返回类型为void,形参为复数类对象的引用Complex&c。当
9、程序执行主函数中的赋值语句c2=c1而遇到赋值运算符“=”时,自动调用赋值运算符“=”重载函数“operator=()”,并将“=”运算符右边的操作数c1作为实参,左边操作数c2作为调用重载函数的对象,即:作了一次c2.operator=(c1)的函数调用。在函数的调用过程中,实参c1传给形参c,在函数体内完成了复数实部与虚部的赋值操作:Real=c1.Real;Image=c1.Image;2.2 二元运算符重载函数l在上例定义复数类中,重载“+”、“”运算符,使这二个运算符能直接完成复数的加、减运算。#includeclassComplexprivate:floatReal,Image;p
10、ublic:Complex(floatr=0,floati=0)Real=r;Image=i;voidShow(inti)/显示输出复数coutci=Real+Imageiendl;Complexoperator+(Complex&c);/“+”运算符重载函数完成两个复数加法Complexoperator-(Complex&c);/“”运算符重载函数完成两个复数减法Complexoperator+(floats);/“+”运算符重载函数完成复数实部加实数voidoperator+=(Complex&c);/“+=”运算符重载函数完成复数=复数+cvoidoperator=(Complex&c)
11、;/“=”运算符重载函数完成两个复数赋值;ComplexComplex:operator+(Complex&c)Complext;t.Real=Real+c.Real;t.Image=Image+c.Image;returnt;ComplexComplex:operator-(Complex&c)Complext;t.Real=Real-c.Real;t.Image=Image-c.Image;returnt;ComplexComplex:operator+(floats)Complext;t.Real=Real+s;t.Image=Image;returnt;voidComplex:oper
12、ator+=(Complex&c)Real=Real+c.Real;Image=Image+c.Image;voidComplex:operator=(Complex&c)Real=c.Real;Image=c.Image;voidmain(void)Complexc1(25,50),c2(100,200),c3,c4;c1.Show(1);c2.Show(2);c3=c1+c2;/c3=(25+50i)+(100+200i)=125+250ic3.Show(3);c4=c2-c1;/c4=(100+200i)(25+50i)=75+150ic4.Show(4);c2+=c1;/c2=c2+c
13、1=(100+200i)+(25+50i)=125+250ic2.Show(2);c1=c1+200;/c1=(25+50i)+200=225+50ic1.Show(1);l执行程序后输出:c1=25+50ic2=100+200ic3=125+250ic4=75+150ic2=125+250ic1=225+50i2.2 二元运算符重载函数l在上例中的主函数中可以看出,经重载后运算符的使用方法与普通运算符一样方便。如复数c1加c2赋给c3的加法运算:c3=c1+c2与普通实数加法形式上完全相同。但实际执行过程中确是完全不同的。实现复数加法运算是通过调用加法运算符重载函数来完成,而对加法运算符重载
14、函数的调用是由系统自动完成的。如表达式:c3=c1+c2;编译器先将c1+c2解释为对“+”运算符重载函数:c1.operator+(c2)的调用。再将该表达式解释为对“=”运算符重载函数:c4.operator=(c1.operator+(c2)的调用。由c1.operator+(c2)成员函数求出复数c1+c2的值t,并返回一个计算结果t,然后再由成员函数c3.operator=(t),完成复数c3=t的赋值运算,将运算结果赋给c3。运算符重载的几个问题运算符重载的几个问题(1)运算符重载函数名必须为:operator(2)运算符的重载是通过调用运算符重载函数实现的,调用函数时,左操作数为
15、调用重载函数的对象,右操作数作为函数的实参,实参可以是对象、实数等其它类型。(3)形参说明若重载函数为成员函数,则参加二元运算的左操作数为调用重载函数的对象。因此,重载函数为成员函数的参数通常为一个,即右操作数。如在上例中,二元加法运算:c1+c2被解释为对重载成员函数c1.operator+(c2)的调用,此时重载函数只有一个参数。运算符重载的几个问题运算符重载的几个问题(4)运算符重载函数的返回类型若二个同类对象进行二元运算后的结果类型仍为原类型,则运算符重载函数的返回类型应为原类型。如在上例中,由于两个复数运算的结果仍为复数,因此上述运算符重载函数的返回类型均为复数类型Complex。运
16、算符重载的几个问题运算符重载的几个问题(5)除了下面几个外,其余的运算符都可以用作重载。下列运算符不允许重载:运算符运算符的含义不允许重载的原因?:三目运算符在C+中没有定义一个三目运算符的语法成员操作符为保证成员操作符对成员访问的安全性,故不允许重载*成员指针操作符同上:作用域运算符因该操作符左边的操作数是一个类型名,而不是一个表达式sizeof求字节数操作符其操作数是一个类型名,而不是一个表达式运算符重载的几个问题运算符重载的几个问题(6)运算符的重载实际上是函数的重载,对运算符重载的选择,遵循着函数重载的选择原则。重载运算符有以下各种限制:不可臆造新的运算符 不能改变运算符操作数的个数;
17、不能改变运算符原有的优先级;不能改变运算符原有的结合性;不能改变运算符原有的语法结构2运算符重载函数为友元函数l运算符重载函数为友元函数的一般定义格式为:(形参1,形参2)函数体其中,类型为运算符重载函数的返回类型。operator为重载函数名。形参1与形参2常为参加运算的两个对象的引用。例:用友元运算符重载函数实现复数的加、减运算。#includeclassComplexprivate:floatReal,Image;public:Complex(floatr=0,floati=0)Real=r;Image=i;voidShow(inti)coutci=Real+Imageiendl;fri
18、endComplexoperator+(Complex&,Complex&);/“+”重载函数为友元函数friendComplexoperator-(Complex&,Complex&);/“”重载函数为友元函数friendComplexoperator+(Complex&,float);Complexoperator+(Complex&c1,Complex&c2)Complext;t.Real=c1.Real+c2.Real;t.Image=c1.Image+c2.Image;returnt;Complexoperator-(Complex&c1,Complex&c2)Complext;t.
19、Real=c1.Real-c2.Real;t.Image=c1.Image-c2.Image;returnt;Complexoperator+(Complex&c,floats)Complext;t.Real=c.Real+s;t.Image=c.Image;returnt;voidmain(void)Complexc1(25,50),c2(100,200),c3,c4;c1.Show(1);c2.Show(2);c3=c1+c2;/c3=(25+50i)+(100+200i)=125+250ic3.Show(3);c4=c2c1;/c4=(100+200i)(25+50i)=75+150ic
20、4.Show(4);c1=c1+200;/c1=25+50i+200=225+50ic1.Show(1);2运算符重载函数为友元函数l程序执行后输出:c1=25+50ic2=100+200ic3=125+250ic4=75+150ic1=225+50i2运算符重载函数为友元函数l从主函数可以看出,用成员函数与友元函数为运算符重载函数,就运算符的使用来讲是一样,但编译器处理方法是不同的,例如对表达式:c3=c1+c2;的处理是,先将c1+c2变换为对友元函数的调用:operator+(c1,c2);再将函数返回结果即两复数的和t赋给复数c3,因此表达式c3=c1+c2;实际执行了c3=opera
21、tor+(c1,c2)的函数调用及赋值工作。l友元函数与成员函数作为二元运算符重载函数的另一个区别是:当重载函数为成员函数时,二元运算符的左操作数为调用重载函数的对象。右操作数为实参。当重载函数为友元函数时,二元运算符的左操作数为调用重载函数的第一个实参。右操作数为第二个实参。2.3 一元运算符的重载 l所谓一元运算符是只有一个操作数的运算符,如自加运算符“+”,自减运算符“”等等。与二元运算符的重载类似,一元运算符重载函数也分为类的成员函数与友元函数两类。2.3 一元运算符的重载1一元运算符重载函数为类的成员函数格式::operator(形参)函数体现对比较典型的一元运算符“+”、“”进行讨
22、论。对于一元运算符“+”、“”存在前置与后置问题,因此定义函数时会有所区别。2.3 一元运算符的重载(1)“+”为前置运算符时,函数格式为::operator+()函数体(2)“+”为后置运算符时,函数格式为:operator+(int)函数体由于是用运算符重载函数来实现“+”运算,所以这里的“+”是广义上的增量运算符。在后置运算符重载函数中,形参int仅用作区分前置还是后置,并无实际意义,可以给一个变量名,也可不给出变量名。例:定义一个描述时间计数器的类,其三个数据成员分别用于存放时、分和秒。用成员函数重载“+”运算符,实现计数器对象的加1运算。#includeclassTCountpriv
23、ate:intHour,Minute,Second;public:TCount(inth=0,intm=0,ints=0)Hour=h;Minute=m;Second=s;TCountoperator+();/定义“前置+”运算符重载成员函数TCountoperator+(int);/定义“后置+”运算符重载成员函数voidShow(inti)/定义显示时:分:秒的成员函数coutti=Hour:Minute:Secondendl;TCountTCount:operator+()Second+;if(Second=60)Second=0;Minute+;if(Minute=60)Minute=
24、0;Hour+;if(Hour=24)Hour=0;return*this;TCountTCount:operator+(int)TCounttemp=*this;Second+;if(Second=60)Second=0;Minute+;if(Minute=60)Minute=0;Hour+;if(Hour=24)Hour=0;returntemp;voidmain(void)TCountt1(10,25,50),t2,t3;/定义时间计数器对象t1=10:25:50t1.Show(1);t2=+t1;/先加后用,即:先将t1自加,然后将t1赋给t2t1.Show(1);t2.Show(2)
25、;t3=t1+;/先用后加,即:先将t1赋给t3,然后将t1自加t1.Show(1);t3.Show(3);2.3 一元运算符的重载l程序执行后输出:t1=10:25:50t1=10:25:51t2=10:25:51t1=10:25:52t3=10:25:512.3 一元运算符的重载l说明:(1)“前置+”运算符重载成员函数的说明在主函数中执行t2=+t1语句时,先将t1自加,然后将t1赋给t2。该语句操作是通过调用“前置+”运算符重载成员函数来实现的。在执行t2=+t1语句时,编译系统将t2=+t1解释为对重载函数的调用:t2=t1.operator+();由于重载函数为对象t1成员函数,所
26、以函数体对Hour、Minute、Second的自加操作就是对t1的数据成员Hour、Minute、Second的自加操作,因而可完成对计数器对象t1的加1操作。为了实现前置“+”运算,应将加1后的对象值t1作为返回值,即用returnt1语句返回当前对象t1值。但在重载函数体内并不能直接使用对象t1,因而无法使用returnt1语句。这时必须使用指向当前对象t1的指针this。由于*this=t1,所以用return*this语句可将自加后的t1值返回给调用函数,并赋给对象t2。由于将对象值t1值作为函数返回值,所以重载函数的类型应与t1的类型相同,为TCount类型。2.3 一元运算符的重
27、载(2)“后置+”运算符重载成员函数的说明在主函数中执行t3=t1+语句时,先将t1赋给t3,然后将t1自加。该语句操作是通过调用“后置+”运算符重载成员函数来实现的。在执行t3=t1+语句时,编译系统将t3=t1+解释为对重载函数的调用:t3=t1.operator+(1);为了实现后置“+”运算,应将加1前的对象值t1作为返回值,这时应使用指向当前对象t1的指针this。在后置重载函数中先用TCount类定义一个临时对象temp,并将t1值(即*this值)赋给temp,在函数最后用returntemp语句将加1前的t1值返回给函数,并赋给对象t2。2.3 一元运算符的重载(3)用成员函数
28、实现一元运算符的重载时,运算符的左操作数或右操作数为调用重载函数的对象。因为要用到隐含的this指针,所以运算符重载函数不能定义为静态成员函数,因为静态成员函数中没有this指针。2.3 一元运算符的重载l2一元运算符重载函数为友元函数一般格式为:operator(类名&对象)函数体对于“+”、“”运算符存在前置运算与后置运算的问题,因此,运算符重载函数必须分为两类。以“+”运算符为例,用友元函数来实现“+”运算符的重载时:前置“+”运算符重载的一般格式为:operator+(类名&);后置“+”运算符重载的一般格式为:operator+(类名&,int);其中:形参为要实现“+”运算的对象,
29、int只是用于区分是前置还是后置运算符,并无整型数的含义。【例】用一个类来描述时间计数器,用三个数据成员分别存放时、分和秒。用友元函数重载“+”运算符,实现计数器对象的加1运算符。#includeclassTCountprivate:intHour,Minute,Second;public:TCount()Hour=Minute=Second=0;TCount(inth,intm,ints)Hour=h;Minute=m;Second=s;friendTCountoperator+(TCount&t);/定义“前置+”运算符重载友元函数friendTCountoperator+(TCount&
30、t,int);/定义“后置+”运算符重载友元函数voidShow(inti)coutti=Hour:Minute:Secondendl;TCountoperator+(TCount&t)t.Second+;if(t.Second=60)t.Second=0;t.Minute+;if(t.Minute=60)t.Minute=0;t.Hour+;if(t.Hour=24)t.Hour=0;returnt;TCountoperator+(TCount&t,int)TCounttemp=t;t.Second+;if(t.Second=60)t.Second=0;t.Minute+;if(t.Minu
31、te=60)t.Minute=0;t.Hour+;if(t.Hour=24)t.Hour=0;returntemp;voidmain(void)TCountt1(10,25,50),t2,t3;/t1=10:25:50t1.Show(1);t2=+t1;/先加后用t1.Show(1);t2.Show(2);t3=t1+;/先用后加t1.Show(1);t3.Show(3);l程序执行后输出:t1=10:25:50t1=10:25:51t2=10:25:51t1=10:25:52t3=10:25:51l说明:(1)对“前置+”运算符重载友元函数的说明在主函数中t2=+t1语句的含义是:先将t1自
32、加,然后将自加后的t1值赋给t2。该语句操作是通过调用“前置+”运算符重载友元函数来实现的。在执行t2=+t1语句时,编译系统将t2=+t1解释为对重载函数的调用:t2=operator+(t1);为了实现对t1的自加操作,重载函数的形参t必须与实参t1占用同一内存空间,使对形参t的自加操作变为对实参t1的自加操作。为此,形参t必须定义为时间计数器类TCount的引用,即:TCount&t。此外,为了能将t自加的结果通过函数值返回给t2,重载函数的返回类型必须与形参t相同,即为时间计数器类TCount的引用。故“前置+”运算符重载友元函数定义为:TCount&operator+(TCount&
33、t)/函数返回类型与形参t相同,均为TCount&t.Second+;returnt;当系统自动调用“前置+”运算符重载友元函数时,对形参t与实参t1自加后,用returnt语句将自加的结果通过函数返回并赋给t2。从而实现对t1先加后赋值给t2的操作。(2)对“后置+”运算符重载友元函数的说明在主函数中t3=t1+语句的含义是:先将t1当前值赋给t3,然后再对t1自加。该语句操作是通过调用“后置+”运算符重载友元函数来实现的。在执行t3=t1+语句时,编译系统将t3=t1+解释为对重载函数的调用:t3=operator+(t1,1);为了实现对t1的自加操作,重载函数的形参t必须与实参t1占用
34、同一内存空间,使对形参t的自加操作变为对实参t1的自加操作。为此,形参t必须定义为时间计数器类TCount的引用,即:TCount&t。此外,为了能将t自加前的结果通过函数值返回给t3,在重载函数内第一条语句定义了TCount类的临时对象temp,并将自加前t值赋给temp,在函数的最后用returntemp语句返回自加前的t值。重载函数的返回类型必须与对象temp相同,即为TCount类型。故“后置+”运算符重载友元函数定义为:TCountoperator+(TCount&t,int)/函数返回类型与temp相同,均为TCount类型TCounttemp=t;t.Second+;return
35、temp;当系统自动调用“后置+”运算符重载友元函数时,对形参t与实参t1自加后,用returntemp语句将自加前的结果通过函数返回并赋给t3。从而实现先将t1赋给t3后将t1自加的操作。2.3 一元运算符的重载【例】用一个类来描述人民币币值,用两个数据成员分别存放元和分。重载“+”运算符,用运算符重载成员函数实现对象的加1运算。#include#includeclassMoneyprivate:floatDollars,Cents;/定义数据成员元与分public:Money()/定义默认的构造函数Dollars=Cents=0;Money(float,float);/定义双参数构造函数M
36、oney(float);/定义单参数构造函数Moneyoperator+();/定义前置“+”运算符重载成员函数Moneyoperator+(int);/定义后置“+”运算符重载成员函数floatGetAmount(float&n)/通过形参n返回元,通过函数返回分n=Dollars;returnCents;Money();/缺省的析构函数voidShow()/定义显示元与分的成员函数coutDollars元Cents分=100)/若分大于100,则元加1,分减100Dollars+;Cents=Cents100;return*this;/返回自加后的人民币对象值MoneyMoney:oper
37、ator+(int)Moneytemp=*this;/将自加前人民币对象值存入临时对象tempCents+;/分加1if(Cents=100)/若分大于100,则元加1,分减100Dollars+;Cents=100;returntemp;voidmain(void)Moneym1(25,50),m2(105.7),m3(10.5,125);/m1=25元50分,m2=105元70分,m3=10.5+125/100=11.75元Moneyc,d;floate1,f1,e2,f2;m1.Show();c=+m1;/先加后用,即:先将m1加1,然后将m1赋给c(c=m1=25元51分)d=m1+;
38、/先用后加,即:先将m1赋给d(d=m1=25元51分)。然后将m1加1(m1=25元52分)c.Show();d.Show();c=+m2;/c=m2=105元71分d=m2+;/d=105元71分,m2=105元72分c.Show();d.Show();e1=m2.GetAmount(f1);/m2=105元72分,f1=105e1=72e2=m3.GetAmount(f2);/m3=11元75分,f2=11,e2=75coutf1+f2元te1+e2分endl;/f1+f2=105+11=116/e1+e2=72+75=147程序执行后输出:25元50分25元51分25元51分105元7
39、1分105元71分116元147分l说明:(1)Money为描述人民币的类,其数据成员Dollars、Cents分别代表元与分。(2)在单参数的构造函数中,使用标准函数modff(n,&num)将实数n分为解为整数与小数两部分,返回小数值,整数值送到num所指单元中。最后将整数存入元Dollars中,小数部分乘100后存入分Cents中。(3)前置“+”运算符重载函数中,先对人民币的分加1运算,分加1存在进位问题,当分加满100后,将分Cents减100(即分清零),再将元Dollars加1,最后通过return*this语句返回自加后的人民币币值。(4)后置“+”运算符重载函数中,先将当前人
40、民币币值赋给临时对象temp,然后对人民币的分加1运算,当分加满100后,将分Cents减100,再将元Dollars加1,最后通过returntemp返回自加前的人民币币值。(5)主函数中c=+m1语句应解释为对前置重载函数的调用:c=m1.opreator();d=m1+语句应解释为对后置重载函数的调用:d=m1.opreator(1);【例】定义描述三维空间点(x,y,z)的类,用友元函数实现“+”运算符的重载。#includeclassThreeDfloatx,y,z;public:ThreeD(floata=0,floatb=0,floatc=0)x=a;y=b;z=c;ThreeD
41、operator+(ThreeD&t)/二个点坐标相加的“+”运算符重载成员函数ThreeDtemp;temp.x=x+t.x;temp.y=y+t.y;temp.z=z+t.z;returntemp;friendThreeD&operator+(ThreeD&);/坐标点前置“+”运算符重载友元函数friendThreeDoperator+(ThreeD&,int);/坐标点后置“+”运算符重载友元函数ThreeD()voidShow()coutx=xty=ytz=z”等运算操作符完成,而必须通过字符处理函数来完成。例如,有字符串s1=”ABC”,s2=”DEF”,要完成s=s1+s2=“A
42、BCDEF”的工作,则需要调用字符串处理函数:strcpy(s,s1)与strcat(s,s2)才能完成两个字符串的拼接工作。l通过C+提供的运算符重载机制,可以提供对字符串直接操作的能力,使得对字符串的操作与对一般数据的操作一样方便。如字符串s1与s2拼接成字符串s的工作,用“+”与“=”运算符组成的表达式:s=s1+s2即可完成。l下面通过例题说明字符串运算符重载函数的编写方法,及重载后字符串运算符的使用方法。【例】编写字符串运算符“=”、“+”、“”的重载函数,使运算符“=”、“+”、“”分别用于字符串的赋值、拼接、比较运算,实现字符串直接操作运算。分析:字符串可用指向字符串的指针Sp及
43、字符串长度Length来描述,如图所示。因此描述字符串类的数据成员为字符指针Sp及其长度Length。设计缺省构造函数、拷贝构造函数及初始化构造函数。再设计“=”、“+”、“”运算符重载函数,分别完成字符串赋值、拼接、比较运算。在主函数中先定义字符串对象,并调用构造函数完成初始化工作。然后使用“=”、“+”、“”运算符,直接完成字符串的赋值、拼接、比较运算。程序设计如下:#include#includeclassString/定义字符串类protected:intLength;char*Sp;public:String()/定义缺省的构造函数Sp=0;Length=0;String(const
44、String&);/定义拷贝构造函数String(constchar*s)/定义初始化构造函数Length=strlen(s);Sp=newcharLength+1;strcpy(Sp,s);String()/定义析构函数if(Sp)deleteSp;voidShow()/定义显示字符串函数coutSp(constString&);/定义字符串比较成员函数;String:String(constString&s)Length=s.Length;if(s.Sp)Sp=newcharLength+1;strcpy(Sp,s.Sp);elseSp=0;voidString:operator=(Str
45、ing&s)if(Sp)deleteSp;Length=s.Length;if(s.Sp)Sp=newcharLength+1;strcpy(Sp,s.Sp);elseSp=0;Stringoperator+(constString&s1,constString&s2)Stringt;t.Length=s1.Length+s2.Length;t.Sp=newchart.Length+1;strcpy(t.Sp,s1.Sp);strcat(t.Sp,s2.Sp);returnt;intString:operator(constString&s)if(strcmp(Sp,s.Sp)0)return
46、1;else0;voidmain(void)Strings1(software),s2(hardware),s3(design);Strings4(s1),s5,s6,s7;s5=s2;s6=s4+s3;s7=s5+s3;s6.Show();s7.Show();if(s4s5)s4.Show();elses5.Show();l程序执行后输出:softwaredesignhardwaredesignsoftware2.4 字符串类运算符重载 l关于上述程序有几点说明如下:(1)定义初始化构造函数中:String(constchar*s)Length=strlen(s);Sp=newcharLen
47、gth+1;strcpy(Sp,s);形参为字符串指针变量s,为了防止在构造函数内修改实参字符串的值,特在形参类型前加关键词const,表示在构造函数内,s所指字符串是不能修改的。初始化构造函数体内,先用字符串函数strlen求出字符串s的长度,并赋给Length。然后用new运算符动态建立字符数组,将字符数组首地址赋给字符串指针Sp,最后用字符串拷贝函数strcpy将字符串s拷贝到Sp所指字符串中。完成String类对象数据成员Length与Sp的初始化工作。2.4 字符串类运算符重载(2)字符串赋值“=”运算符重载成员函数中:voidString:operator=(String&s)if
48、(Sp)deleteSp;Length=s.Length;if(s.Sp)Sp=newcharLength+1;strcpy(Sp,s.Sp);elseSp=0;形参为String类的引用s。在函数体内先删除当前字符串内容。然后将形参字符串长度赋给当前对象的字符串长度Length。将形参字符串内容赋给当前对象。2.4 字符串类运算符重载(3)因为字符串“+”运算符重载函数为友元函数,因此参加运算的两个字符串必须以形参方式输入函数体内,所以重载函数的形参为两个String类型的对象的引用。函数体内先定义一个String类型的临时对象t,用于存放两个字符串拼接的结果。再将两个字符串的长度之和赋给t
49、的长度t.Length,用new运算符动态分配长度为t.Length+1的内存空间,并将其地址赋给t.Sp。再用strcopy()函数将s1拷贝到t,用strcat()将s2拼接到t中,完成t=s1+s2的字符串拼接工作,最后将t返回给调用对象。由于函数返回值为对象t,所以,重载函数的返回类型为String。2.4 字符串类运算符重载(4)在主函数中:字符串赋值运算语句s5=s2;被编译器解释为对“=”运算符重载函数的调用:s5.opreator=(s2);字符串拼接运算语句s6=s4+s3;被编译器解释为对“+”与“=”运算符重载函数的调用:s6.opreator=(opreator+(s4
50、,s3);字符串比较运算语句s4s5;被编译器解释为对“”运算符重载函数的调用:s4.opreator(s5);2.5 赋值运算符和赋值运算符重载 l相同类型的对象之间是可以直接赋值的,在前面的程序例子中已多次使用。但当对象的成员中使用了动态数据类型时,就不能直接相互赋值,否则在程序执行期间会出现运算错误。l【例】对象间直接赋值导致程序执行的错误。#include#includeclassStringprivate:char*ps;public:String()ps=0;String(char*s)ps=newcharstrlen(s)+1;strcpy(ps,s);String()if(ps