c+++多态性++课件+讲座.ppt_第1页
c+++多态性++课件+讲座.ppt_第2页
c+++多态性++课件+讲座.ppt_第3页
c+++多态性++课件+讲座.ppt_第4页
c+++多态性++课件+讲座.ppt_第5页
已阅读5页,还剩128页未读 继续免费阅读

下载本文档

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

文档简介

1、1,第五章 多态性,2,5.1 编译时的多态性与运行时的多态性,多态性是指用同一个名字定义不同的函数,这些函数执行不同但又类似的操作。 联编的概念: 一个源程序经过编译、连接、成为可执行文件的过程是把可执行代码联编(或称装配)在一起的过程。 静态联编(前期联编) 静态联编要求在程序编译时就知道调用哪个函数,就决定如何实现某一动作。 动态联编(后期联编、滞后联编) 一直要到程序运行时才能确定调用哪个函数。系统在运行时才动态完成的联编。 静态联编支持的多态性称为编译时多态性,也称静态多态性。在C+中,编译时多态性是通过函数重载和运算符重载实现的。 动态联编支持的多态性称为运行时多态性,也称动态多态

2、性。在C+中,运行 时多态性是通过继承和虚函数来实现的。,3,5.2 函数重载,编译时多态性可以通过函数重载来实现。函数重载的意义在于它能用同一个名字访问一组相关的函数,也就是说,能使用户为某一类操作取一个通用的名字,而由编译程序来选择具体由哪个函数来执行,因而有助于解决程序的复杂性问题。普通成员函数和构造函数都可以重载 例5.1 基类和派生类中函数重载的例子 #include class point int x,y; public: point(int a,int b)x=a;y=b; float area()return 0.0; /基类中的area函数 ; class circle:pu

3、blic point int radius; public: circle(int x,int y,int rad):point(x,y)radius=rad; float area()return 3,1416*radius*radius;/派生类中的area函数 ;,Void main() point p(20,20); circle c(8,8,30); coutp.area()endl; /执行基类point中的area()的函数 coutc.area()endl;/执行派生类circle中的area()函数 coutc.point:area()endl;/执行基类point中的are

4、a()的函数 程序运行结果为: 0 2827.439941 0,4,说明:,在基类和派生类中的函数重载有两种情况: 1.参数有所差别的重载,这种重载函数的定义和调用方法在前面章节已进行了介绍;在编译时根据参数不同来区分函数重载。 2.函数所带的参数完全相同,只是它们属于不同的类。这时要人工干预,以下两种方法可以使编译时区别这类函数: (1)使用对象名加以区分。例如:p.area()和c.erea()分别调用类point的area()函数和类circle的area()函数。 (2)使用“类名:”加以区分。例如:point:area()和circle:area()分别调用类point和类circl

5、e的area()函数。,5,5.3 运算符重载,在C+中,除了可以对函数重载外,还可以对大多数运算符实施重载。 运算符重载通过创建运算符函数operator()来实现。运算符函数定义了重载的运算符将要进行的新的操作,这种操作通常作用在一个类上。 函数operator()可以 外部函数 类的友元函数 是类的成员函数,6,5.3.1 类以外的运算符重载,对基本的数据类型,C+提供了许多预定义的运算符,如“+”、“-”、“*”、“/”、“=” 等,若有一个复数类 complex: class complex public: double real,imag; complex(double r=0,d

6、ouble i=0) real=r;imag=i; ; 若要把类complex的两个对象com1和com2加在一起,下面的语句是不能实现的: void main() complex com1(1.1,2.2), com2(3.3,4.4), total; total=com1+com2;/错误 /. 错误原因是类complex的类型不是基本数据类型,而是用户自定义的数据类型。C+还是无法直接将两个complex类对象相加。,7,类外部的运算符函数,为了表达上的方便,人们希望预定义的内部运算符(如“+”、“-”、“*”、“/”等)在特定类的对象上以新的含义进行解释,如希望能够实现total=co

7、m1+com2,这就需要用重载运算符来解决。 C+为运算符重载提供了一种方法,即在进行运算符重载时,必须写一个运算符函数,其名字为operator后随一个要重载的运算符。例如,要重载“+”号,应该写一个名字为 operator+ 的函数。 表5.1 运算符函数,8,运算符函数operator+(),在编译时遇到名为operator的运算符函数(表示所要重载的运算符),就检查传递给函数的参数的类型。如果编译器在一个运算符的两边看到自定义的数据类型,就执行用户自己的函数,而不是常规运算符。 若要将上述类complex的两个对象相加,只要写一个运算符函数operator+() complex ope

8、rator+(complex om1,complex om2) complex temp; temp.real=om1.real+om2.real; temp.imag=om1.imag+om2.imag; return temp; 我们就能方便的使用语句 total=com1+com2; 将类complex的两个对象com1和com2相加。 也可以使用以下的调用语句,将两个complex类对象相加: total=operator+(com1,com2); 这两个调用语句是等价的,但显然后者不如前者简明和方便。,9,例 5.2 运算符函数operator+()将两个complex类对象相加程序

9、,#include class complex public: double real; double imag; complex(double r=0,double i=0) real=r;imag=i; ; complex operator+(complex co1,complex co2) complex temp; temp.real=co1.real+co2.real; temp.imag=co1.imag+co2.imag; return temp; ,Void main() complex com1(1.1,2.2),com2(3.3,4.4), total1, total2;

10、total1=operator+(com1,com2); /调用运算符函数operator+()的第一种方式 coutreal1=total1.real” imag1=total1.imagendl; total2=com1+com2;/调用运算符函数operator+()的第二种方 coutreal2=total2.real” imag2=total2.imagendl; 程序运行结果为: real1=4.4imag1=6.6 real2=4.4imag2=6.6,10,综合说明:,(1)运算符重载函数operator ()可以返回任何类型,甚至可以是void类型但通常返回类型与它所操作的类

11、的类型相同,这样可以使重载运算符用在复杂的表达式中。 (2)在重载运算符时,运算符函数所作的操作不一定要保持C+中该运算符原有的含义。例如,可以把加运算符重载成减操作,但这样容易造成混乱。所以保持原含义,容易被接受,也符合人们的习惯。 (3)在C+中,用户不能定义新的运算符,只能从C+已有的运算符中选择一个恰当的运算符重载。 (4)C+编译器根据参数的个数和类型来决定调用哪个重载函数。因此,可以为同一个运算符定义几个运算符重载函数来进行不同的操作 (5)重载运算符与预定义运算符的使用方法完全相同,它不能改变原有运算符的参数个数(单目或双目),也不能改变原有的优先级和结合性。 (6)在C+中,大

12、多数系统预定义的运算符都能被重载,例如+-* /%,12,在类外,友元运算符函数与定义一般的友元函数相似,其格式如下: 返回类型 operator 运算符(参数表) /函数体 由于友元函数不是类的成员函数,所以不需要缀上类名。与成员运算符函数不同,友元运算符函数是不属于任何类对象的,它没有this指针。若重载的是双目运算符,则参数表中有两个操作数;若重载的是单目运算符,则参数表中只有一个操作数。,13,2双目运算符重载,当用友元函数重载双目运算符时,两个操作数都要传给运算符函数。 例5.3 友元函数重载双目运算符 两个复数a+bi和c+di进行加、减、乘、除的方法如下: 加法:(a+bi)+(

13、c+di)=(a+c)+(b+d)i 减法:(a+bi)-(c+di)=(a-c)+(b-d)i 乘法:(a+bi)*(c+di)=(ac-bd)+(ad+bc)i 除法:(a+bi)/(c+di)=(a+bi)*(c-di)/(c*c+d*d),14,#include class complex private: double real; double imag; public: complex(double r=0.0,double I=0.0) real=r; imag=i; void print(); friend complex operator + (complex a,compl

14、ex b); /用友元运算符函数重载复数 “+” friend complex operator (complex a,complex b); /用友元运算符函数重载复数 “-” friend complex operator * (complex a,complex b); /用友元运算符函数重载复数 “*” friend complex operator / (complex a,complex b); /用友元运算符函数重载复数 “/” ;,15,接1 例5.3,complex operator +(complex a,complex b) /重载“+”定义 complex temp;

15、temp.real=a.real+b.real; temp.imag=a.imag+b.imag; return temp; complex operator-(complex a,complex b)/重载“-”定义 complex temp; temp.real=a.real-b.real; temp.imag=a.imag-b.imag; return temp; complex operator (complex a,complex b)/重载“*”定义 complex temp; temp.real=a.real*b.real-a.imag*b.imag; temp.imag=a.r

16、eal*b.imag+a.imag*b.real; return temp; ,16,接2 例5.5,complex operator/(complex a,complex b) /重载“/”定义 complex temp; double t; t=1/(b.real*b.real+b.imag*b.imag); temp.real=(a.real*b.real+a.imag*b.imag)*t; temp.imag=(b.real*a.imag-a.real*b.imag)*t; return temp; void complex:print() /输出显示复数 cout0) cout“+”

17、; if(imag!=0) coutimag“in” ,17,void main() complexA1(2,3,4.6),A2(3,6,2.8), A3,A4,A5,A6;/定义6个复数对象 A3=A1+A2; /复数相加 A4=A1-A2; /复数相减 A5=A1*a2; /复数相乘 A6=A1/A2; /复数相除 A1.print(); /输出复数A1 A2.print(); /输出复数A2 A3.print();/输出复数相加结果A3 A4.print();/输出复数相减结果A4 A5.print();/输出复数相乘结果A5 A6.print();/输出复数相除结果A6 ,18,程序运

18、行结果如下: 2.3+4.6i 3.6+2.8i 5.9+7.4i -1.3+1.8i -4.6+23i 1.017308+0.486538i 调用时: aa bb; /隐式调用 opreator (aa,bb) /显式调用,19,3单目运算符重载,用友元函数重载单目运算符时,需要一个显式的操作数。 例5.4 用友元函数重载单目运算符“-”例子。 #include class AB int a,b; public: AB(int x=0,int y=0) a=x;b=y; / AB的构造函数 friend AB operator-(AB obj);/声明重载单目运算符“-” void show

19、(); ; AB operator-(AB obj)/定义重载单目运算符“-” obj.a=-obj.a; obj.b=-obj.b; return obj; void AB:show() cout“a”a“”=”bend 程序运行结果如下: a=50 b=60 a=-50 b=-60,void mian() AB ob1(50,60),ob2; ob1.show(); ob2=-ob1; ob2.show(); ,20,使用友元函数重载“+ +”,“- -”这样的运算符,可能会出现的问题,例5.5 #include class coord int x,y; public: coord (in

20、t i=0, int j=0) x=i; y=j; void print( ) cout x:x,y:yendl; friend coord operator+(coord op); ; coord operator + (coord op) +op.x; +op.y; return op; ,21,void main( ) coord ob(10,20); ob.print( ); operator + (ob); /显式调用 ob.print( ); +ob; /隐式调用 ob.print( ); 运行结果: x:10,y:20 x:10,y:20 x:10,y:20 这个运行结果没有达“

21、+”的目的,由于友元函数没有this指针,所以不能引用this指针所指的对象。这个函数是通过传值的方法传递参数的,函数体内对op的所以修改都无法传到函数体外。因此,在operator+函数中,任何内容的改变不会影响产生调用的操作数,也就是说。实际上对象x和y并未增加。,22,为了解决以上问题,使用友元函数重载单目运算符“+”或“”时,应采用引用参数传递操作数( ,23,void main() coord ob(10,20); ob.print(); +ob; /隐式调用友元运算符函数 ob.print(); operator+(ob);/显式调用友元运算符函数 ob.print(); 程序运行

22、的结果如下: x:10,y:20 x:11,y:21 x:12,y:22,24,当用友元函数重载单目运算符时,参数表中有一个操作数,一般而言,采用友元函数重载单目运算符后,可以采用以下两种方法来使用: aa; /隐式调用 operator(aa);/显式调用 综合说明: (1)不能用友元函数重载的运算符是:=,(), ,- 其余的运算符都可以使用友元函数来实现重载。 (2)由于单目运算符“-”可不改变操作数自身的值,所以在例5.4载单目运算符“-” 的友元运算符函数的原型可写成: friend AB operator (AB obj); 通过传值的方式传递参数。,25,5.3.3 成员运算符函

23、数,运算符函数可以定义为类的成员(称为成员运算符函数) 1. 成员运算符函数定义的语法形式 成员运算符函数的原型在类的内部声明格式为: class X /. 返回类型 operator 运算符(形参表); /. ; 类外成员运算符函数定义的更一般形式为: 返回类型 X:operator 运算符 (形参表) /函数体 在成员运算符函数的参数表中,若运算符是单目的,则参数表为空;若运算符是双目的,则参数表中有一个操作数。,26,2.双目运算符重载,对双目运算符而言,成员运算符函数的参数表中仅有一个参数,它们为运算符的右操作数,此时当前对象作为运算符的左操作数,它们通过this指针隐含地传递给函数的

24、。 例如: class X /. int operator +(X a); ; 在类X中声明了重载“+”的成员运算符函数,返回类型为int,它具有两个操作数,一个是当前对象,另一个是对象a。 例 5.7 用双目运算符函数进行复数运算的例子,27,#include class complex private: double real; /复数的实数部分 double imag; /复数的虚数部分 public: complex(double r=0.0,double i=0.0); /构造函数 void print(); /显示输出复数 complex operator +(complex c)

25、; /重载复数“+”运算符 complex operator -(complex c); /重载复数“-”运算符 complex operator *(complex c); /重载复数“*”运算符 complex operator /(complex c); /重载复数“/”运算符 ; complex:complex(double r,double i) /定义构造函数 real=r;imag=i;,28,接1 例5.7,complex complex:operator +(complex c) /重载“+”定义 complex temp; temp.real=real+c.real; te

26、mp.imag=imag+c.imag; return temp; complex complex:operator -(complex c) /重载“-”定义 complex temp; temp.real=real-c.real; temp.imag=imag-c.imag; return temp; ,29,接2 例5.7,complex complex:operator *(complex c) /重载“*”定义 complex temp; temp.real=real*c.real-imag*c.imag; temp.imag=imag*c.real+real*c.imag; ret

27、urn temp; complex complex:operator /(complex c) /重载“/”定义 complex temp; double t; t=1/(c.real*c.real+c.imag*c.imag); temp.real=(real*c.real+imag*c.imag)*t; temp.imag=(c.real*imag-real*c.imag)*t; return temp; ,30,接3 例5.7,void complex:print() /显示复数的实数部分和虚数部分 cout0)cout+; if(imag!=0)coutimagin; void mai

28、n() complex A1(2.3,4.6),A2(3.6,2.8),A3,A4,A5,A6; /定义六个复数类对象 A3=A1+A2;/复数相加 A4=A1-A2;/复数相减 A5=A1*A2;/复数相乘 A6=A1/A2;/复数相除 A1.print();/输出复数A1 A2.print();/输出复数A2 A3.print();/输出复数相加的结果A3 A4.print();/输出复数相减的结果A4 A5.print();/输出复数相乘的结果A5 A6.print();/输出复数相除的结果A6 ,程序运行结果如下: 2.3+4.6i 3.6+2.8i 5.9+7.4i -1.3+1.8

29、i -4.6+23i 1.017308+0.486538i,31,在主函数main()中的语句,A3=A1+A2; A4=A1-A2; A5=A1*A2; A6=A1/A2; 所用的运算符“+”、“-”、“*”、“/”是重载后的运算符。程序执行到这四条语句时C+将其解释为: A3=A1.operator +(A2); A4=A1.operator -(A2); A5=A1.operator *(A2); A6=A1.operator /(A2); 由此我们可以看出,成员运算符函数operator 实际上是由双目运算符左边的对象A1调用的,尽管双目运算符函数的参数表只有一个操作数A2,但另一个操

30、作数是由对象A1通过this指针隐含地传递的。以上两组语句的执行结果是完全相同的。一般而言,采用成员函数重载双目运算符后,可以用以下两种方法来使用: aa bb; /隐式调用 aa.operator (bb); /显式调用 成员运算符函数operator 所需的一个操作数由对象aa通过this指针隐含地传递。因此,它的参数表中只有一个操作数bb。,32,3.单目运算符重载,对单目运算符而言,成员运算符函数的参数表中没有参数,此时当前对象作为运算符的一个操作数。 例5.8 重载单目运算符“+”的例子 #include class coord int x,y; public: coord(int

31、i=0,int j=0); void print(); coord operator +(); /声明成员运算符函数operator +() ; coord:coord(int i,int j) x=i;y=j; void coord:print() cout x:x,y:yendl; coord coord:operator +() /定义成员运算符函数operator +() +x; +y; return *this; ,33,接1 例5.8,void main() coord ob(10,20); ob.print(); +ob; /隐式调用成员运算符函数operator+( ) ob.

32、print(); ob.operator +(); /显式调用成员运算符函数operator +() ob.print(); 程序运行结果如下: x:10, y:20 x:11, y:21 x;12, y=22 本例主函数main()中调用成员运算符函数operator+()采用了两种方法: +ob; 与 ob.operator+() 两者是等价的,其执行效果是完全相同的。 从本例还可以看出,当成员函数重载单目运算符时,没有参数被显式地传递给成员运算符函数。参数是通过this指针隐含地传递给函数的。,34,采用成员函数重载单目运算符时,可以用以下两种方法来使用: aa; /隐式调用 aa.op

33、erator (); /显式调用 成员运算符函数operator 所需的一个操作数由对象aa通过this指针隐含地传递。因此,在它的参数表中没有参数。,35,5.3.4成员运算符函数与友元运算符函数的比较,我们对成员运算符函数与友元运算符函数作一比较。 (1)对双目运算符,成员运算符函数带有一个参数,友元运算符函数带有两个参数对单目运算符,成员运算符函数不带参数,友元运算符函数带有一个参数。 (2)双目运算符一般可以被重载为友元运算符函数或成员运算符函数,但有一种情况,必须使用友元函数。 例如,在例5.4的 类AB 中,用成员运算符函数重载“+”运算 AB AB:operator+(int x

34、) AB temp; temp.a=a+x; temp.b=b+x; return temp; ,36,若类AB的对象ob要做赋值运算和加法运算,以下是一条正确的语句 ob=ob+100; 由于对象ob是运算符“+”的左操作数,所以它调用了“+”运算符重载函数,把一个整数加到了对象ob的某些元素上去。然而,下一条语句就不能工作了: ob=100+ob; 不能工作的原因是运算符的左操作数是一个整数,而整数是一个内部数据类型,100不能产生对成员运算符函数的调用。,37,用两种形式的友元函数来重载运算符函数“+”,就能消除由于运算符“+”的左操作数是内部数据类型而带来的问题,下述程序说明了如何实现

35、。 例5.9 用两种形式的友元函数来重载运算符函数“+” #include class AB int a,b; public: AB(int x=0,int y=0) a=x;b=y friend AB opterator +(AB ob,int x); /声明一种友元运算符函数 friend AB opterator +(int x,AB ob); /声明另一种友元运算符函数 void show(); ;,38,接1 例5.9,AB operator +(AB ob,int x) /定义常规类型在右边的友元运算符函数 AB temp; temp.a=a+x; temp.b=b+x; retu

36、rn temp; AB operator +(int x ,AB ob) /定义常规类型在左边的友元运算符函数 AB temp; temp.a=x+ob.a; temp.b=x+ob.b; return temp; void AB:show() cout“a=”a” “b=“b“n”; ,void main() AB ob1(30,40),ob2; ob2=ob1+30; ob2.show(); ob2=50+ob1; ob2.show(); ,39,(3)成员运算符函数和友元运算符函数都可以用习惯方式调用,也可以用它们专用的方式调用,表5.2列出了一般情况下运算符函数的调用形式。 习惯形式

37、友元运算符函数调用形式 成员运算符函数调用形式 a+b operator+(a,b) a.operator+(b) -a operator-(a) a.operator-() a+ operator+(a,0) a.operator+(0) (4) c+的大部分运算符既可说明为成员运算符函数,又可说明为友元运算符函数。究竟选择哪一种运算符函数好一些,没有定论,这主要取决于实际情况和程序员的习惯。 一般而言,对于双目运算符,将它重载为一个友元运算符函数比重载为一个成员运算符函数便于使用。若一个运算符的操作需要修改类对象的状态,则选择成员运算符函数较好。如果运算符所需的操作数(尤其是第一个操作数)

38、希望有隐式类型转换,则运算符重载必须用友元函数,而不能用成员函数。,40,有以下的经验: 对于单目运算符,建议选择成员函数; 对于运算符“=、( )、 、-”只能作为成员函数; 对于运算符“+=、-=、/=、*=、 +ob; 在C+2.1及以后的版本中,编辑器可以通过在运算符函数参数表中是否插入关键字 int 来区分这两种方式。 (1) 前缀方式 +ob,可以用运算符函数重载为: ob.operator+(); /成员函数重载 operator+(X /友元函数重载 调用时,参数 int 一般用0值。 重载运算符“- -”也可用类似的方法。,42,例5.10 包含“+”和“-”两种重载运算符,

39、#include #include class over int i1, i2, i3; public: void init(int I1, int I2, int I3) i1=I1; i2=I2; i3=I3; /给数据成员赋初值 void print(); cout“ i1:”i1” i2:”i2” i3:”i3endl; /显示输出数据成员 over operator+(); /成员函数重载“+”(前缀方式)声明 over operator+(int); /成员函数重载“+”(后缀方式)声明 friend over operator- -(over +i2; +i3; return *

40、this: over over:operator+(int) /定义成员函数重载+”(后缀方式) i1+; i2+; i3+; return *this; over operator- -(over ,44,接2 例5.10,Void main() over obj1, obj2, obj3, obj4; obj1.init(4,2,5); obj2.init(2,5,9); obj3.init(8,3,8); obj4.init(3,6,7); +obj1; /隐式调用over operator+() obj2+; /隐式调用over operator+(int) -obj3; /隐式调用o

41、ver operator- -(over ,程序运行结果如下: i1:5 i2:3 i3:6 i1:3 i2:6 i3:10 i1:7 i2:2 i3:7 i1:2 i2:5 i3:6 - i1:6 i2:4 i3:7 i1:4 i2:7 i3:11 i1:6 i2:1 i3:6 i1:1 i2:4 i3:5 以上例子中,使用成员函数分别以前缀方式和后缀方式重载了运算符“+”,使用友元函数分别以前缀方式和后缀方式重载了运算符“- -”。,45,536赋值运算符“=”的重载,对任一类X,如果没有用户自定义的赋值运算符函数,那么系统将自动地为其生成一个默认的赋值运算符函数,例如: XX:opera

42、tor=(const X source) /成员间赋值 若obj1和obj2是类X的两个对象,obj2已被创建,则编译程序遇到如下语句: obj1=obj2; 就调用默认的赋值运算符函数,将对象obj2的数据成员逐域拷贝到对象obj1中。 通常,默认的赋值运算符函数是能够胜任工作的。但在某些特殊情况下,如类中有指针类型时,使用默认赋值运算符函数会产生错误,这个错误叫“指针悬挂”,这时程序员不得不自行重载赋值运算符,请看下面的例子。 1. 指针悬挂问题,46,例511,#include #include class string char *ptr; public: string(char *s

43、) ptr=new charstrlen(s)+1; strcpy(ptr,s); string() delete ptr; void print() contptrendl; ; 程序运行结果如下: p2:chen p1: Null Point assignment,void main() string p1(chen); string p2( ); p2=p1; /string 类对象间赋值 contp2:; p2.print(); coutp1:; p1.print(); ,47,接1 例5.11,运行上述程序输出p1时发生错误。原因是执行到赋值语句p2=p1时,实际是使对象p2的指针p

44、tr与对象p1的指针ptr指向new开辟的同一个空间。当p2的生命周期(内层的一对花括号间)结束时,系统自动调用析构函数将这一空间撤消。这样,p2中的ptr原来所指向的区域被封锁起来,并不能再被使用,这就产生了指针悬挂问题。这时尽管p1的指针ptr存在,其所指向的空间却无法访问了,如图所示。当p1的生命走其结束时,将再次调用析构函数,释放同一空间,从而导致运行错误。,48,49,2. 显式地定义一个赋值运算符重载函数,解决指针悬挂问题,例512显式地定义一个赋值运算符重载函数,使P1和P2有各自的存储区。 #include #include class string char *ptr; pu

45、blic: string(char *) ptr=new charstrlen(s)+1; strcpy(ptr,s); string() delete ptr; void print() countptrendl; string ,void main() string p1(chen); string p2 ( ); p2=p1; coutp2:; p2.print(); coutp1:; p1.print(); ,程序运行结果如下: p2:chen p1:chen,50,说明:,(1)赋值运算符“=”只能重载为成员函数,而不能把它重载为友元函数,因为若把上述赋值运算符“=”重载为友元函数:

46、 friend string 可被解释为: X.operator (5); 对运算符 “ ” 重载定义只能使用成员函数,其形式如下: 返回类型 类名:operator (形参) / 函数体 注意:形参只能有一个。,52,重载运算符“ ”来处理数组成员的例子,例513 #include #include class Vector4 private: int v4; public: Vector4(int a1, int a2, int a3, int a4) v0=a1;v1=a2;v2=a3;v3=a4; ; void main() Vector4 v(1,2,3,4); coutv2;/出错

47、,不能访问私有成员。 即使把 int v4; 改为公有成员也出错。要用v.v2,53,我们可用重载运算符“ ” 的方法,方便的引用数组成员。 例514 #include #include class Vector4 private: int v4; public: Vector4(int a1, int a2, int a3, int a4) v0=a1;v1=a2;v2=a3;v3=a4; int ,54,接1 例5.14,void main() Vector4 v(1,2,3,4); coutv2endl; v3=v2; coutv3endl; v2=22; coutv2endl; 在上述

48、程序中,并没有创建Vector4的对象数组。程序中的下标被重载,以便在使用Vector4的对象内的数组成员时,用一种特殊的方式工作。下标总是返回和下标对应的对象内数组成员的那个元素v 。 重载下标运算符“ ”时,返回一个int的引用,可使重载的“ ”用的赋值语句的左边,因为在main () 中,可对某个数组成员元素v 赋值。这样,虽然v 是私有的,main()还是能够直接对其赋值,而不需要使用函数init(),55,在上述程序中,设有对下标的检验,以确保被赋值的数组元素的存在,当程序中一旦出现向超出所定义的数组下标范围的数组元素的赋值,便自动终止程序,以免造成不必要的破坏。 与函数调用运算符“

49、()”一样,下标运算符“ ”不能用友元函数重载,只能采用成员函数重载。 下面再举一个很有意思的例子: 例如,可以对string数据类型定义以下的“ ”运算符重载函数: class string char *ptr; / public: string(const char *); char ,56,其中重载“ ”的operator函数定义为: char 因而op的新值为 “adcd,57,5.3.8 函数调用运算符“()” 的重载,C+中运算符“( )”可作函数调用,函数调用的一般使用格式为: ( ) 我们可以对运算符“( )” 进行重载,使它起别的作用。 在重载“( )”时,C+也把它看成双目

50、运算符,例如X(Y)可看成 ( ) 双目运算符 X 左操作数 Y 右操作数 设X是某个类的对象,类中定义了重载下标运算符“( )”: operator( )函数。 则表达式 X(5); 可被解释为: X.operator( )(5); 对运算符 “ ” 重载定义只能使用成员函数,其形式如下: 返回类型 类名:operator( ) (形参表) / 函数体 注意:形参只能有一个。,58,例 5.15 #include classMatrix int *m; int row, col; public: Matrix(int, int); int ,59,int 运行结果: 34 35,60,再如:

51、对运算符“()” 进行重载,使它起别的作用。,我们知道,双目运算符是由左边的对象产生对operator函数调用的。This指针总是指向产生调用的对象。重载运算符“()”的operator函数可以带任何类型的操作数,返回任何有效的类型。下面的程序将帮助我们理解函数调用运算符“()”的重载。 设obj是类myclass的对象,而且类myclass中定义了重载函数调用运算符“()”,它起的作用是能把对象obj的数据扩大 k 倍和 m 倍。 对应的运算符函数为 myclass operator()(int k, int m) 则函数调用 (把对象obj的数据扩大 10 倍和 100 倍) obj(10

52、,100); 可被解释为: obj.operator()(10,100);,61,例516运算符“()的重载。 #include class myclass int i; float j; public: myclass(int x=0,float y=0) I=x; j=y; myclass operator( )( int k, float m ); /声明重载运算符“()”函数 void display() coutI” jn; ; myclass myclass:operator( )(int k,float m) /定义运算符“()”函数 i=i*k; j=j*m; /把myclas

53、s的对象中的i放大k倍,j放大m倍。 return *this; ,62,void main() myclass obj1(10,11.5); obj1.display(); obj1(10,100); /重载运算符“()”的调用,可解 / 释为obj1.perator()(10,.100) obj1.display(); 程序运行结果为: 10 11.5 100 1150.0 说明:函数调用运算符“()”必须重载为一个成员函数,63,5.4 类型转换,5.4.1 系统预定义类型间的转换 类型转换是将一种类型的值转换为另一种类型值。对于系统预定义类型,C+提供两种类型转换方式,一种是隐式类型转

54、换(或称标准类型转换),另一种是显式类型转换。 (1) 隐式类型转换 隐式类型转换主要遵循以下规则: 在赋值表达式A=B的情况下,赋值运算符右端B的值需转换为A 类型后进行赋值。 当char或short类型变量与int 类型变量进行运算时,将char或short 类型转换成int 类型。 当两个操作对象类型不.一致时,在算术运算前,级别低的自动转换为级别高的类型。,64,(2) 显式类型转换,显式类型常用下述方法表示: 强制转换法 强制转换法的格式为:(类型名)表达式 例如: int i, j / cout(float)(i+j); 将整数i+j的值强制转换成float型后输出。 函数法 函数

55、法函数法的转换格式为: 类型名(表达式) 在上面的例子中,若采用函数法则变为: int i, j; / coutfloat(i+j) 此时也将I+j的值强制转换成float型后输出。,65,5.4.2 类类型与系统预定义类型间的转换,前面介绍的是一般数据类型之间的转换。那么,对于用户自己定义的类类型来讲,如何实现它们与其它数据类型之间的转换呢?通常,可归纳为以下二种方法: 即(1)通过构造函数, (2)通过类型转换函数。 1. 通过构造函数进行类型转换 构造函数具有类型转换的作用,它将其他类型的值装换为它所在类的类型的值。,66,例517,#include class example priv

56、ate: int num; public: example(int); void print (); ; example:example(int n) /由int型向example类类型的转换。 num=n; coutInializing with :numendl; void example:print() coutnum=numendl; 在类example中有一个参数为int 的构造函数example(int),此构造函数可以用来进行类型转换,即完成由int型向example类类型的转换。,67,void main() example X=example(3); X.print(); coutn; example Y=6; Y.print(); 程序执行结果如

温馨提示

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

评论

0/150

提交评论