第八章 多态性与虚函数_第1页
第八章 多态性与虚函数_第2页
第八章 多态性与虚函数_第3页
第八章 多态性与虚函数_第4页
第八章 多态性与虚函数_第5页
已阅读5页,还剩54页未读 继续免费阅读

下载本文档

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

文档简介

1、LOGO1继承和派生v基类、派生类基类、派生类v基类、派生类的构造、析构基类、派生类的构造、析构v继承方式和访问方式继承方式和访问方式v子类型、类型适应子类型、类型适应v名字冲突问题名字冲突问题v重定义,重载重定义,重载v虚基类虚基类LOGO2第八章第八章 多态性和虚函数多态性和虚函数LOGO3Contents函数重载函数重载运算符重载运算符重载静态联编和动态联编静态联编和动态联编虚函数虚函数纯虚函数和抽象类纯虚函数和抽象类虚析构函数虚析构函数程序举例程序举例LOGO4Diagram面向对象面向对象 封装性封装性继承性继承性多态性多态性LOGO5发出同样的消息发出同样的消息被不同类型的对被不同

2、类型的对象接受导致完全象接受导致完全不同的行为不同的行为函数重载和运算函数重载和运算符重载符重载多态性多态性LOGO68.1 函数重载函数重载class Circle public: Circle( ) : xx(0.0) , yy(0.0), rad(1.0) Circle( float x, float y, float radius ) : xx( x ) , yy( y ), rad( radius) Circle( const Circle & C ) xx = C.xx ; yy = C.yy ; rad = C.rad; float diameter() const re

3、turn 2.0 * rad ; float area() const return PI * rad * rad; float circum() const return PI*diameter(); void print() const cout Center is at ( xx , yy ) and Radius = v重载为友元函数的运算符重载函数的格式:重载为友元函数的运算符重载函数的格式:friend operator ()LOGO17class complexpublic: complex(double r=0,double i=0); friend complex opera

4、tor + (const complex &c1,const complex &c2); friend complex operator - (const complex &c1,const complex &c2); friend void print(const complex &c);private: double real,imag;complex operator +(const complex &c1,const complex &c2) return complex(c1.real+c2.real,c1.imag+c2.im

5、ag); LOGO18void main() complex c1(2.5,3.7),c2(4.2,6.5); complex c; c=c1-c2; c.print(); c=c1+c2; c.print();c=operator -(c1,c2);c=operator +(c1,c2);v 二元二元运算符重载为友元函数,要有两个参数。运算符重载为友元函数,要有两个参数。LOGO19两种重载形式的比较两种重载形式的比较 单目运算符一般被重载为成员函数,双目运算符多数单目运算符一般被重载为成员函数,双目运算符多数被重载为友员函数。被重载为友员函数。考虑考虑 x + 27. 5( x为为comp

6、lex类的一个对象类的一个对象 )若重载为友员函数:若重载为友员函数:operator + ( x , 27. 5 ) operator + ( x , complex(27. 5) ) 若重载为成员函数:若重载为成员函数:x. operator + (27. 5) x. operator + (complex(27. 5) 再考虑再考虑 27. 5 + x若重载为友员函数:若重载为友员函数:operator + ( 27. 5 , x ) operator + ( complex(27. 5) , x ) 若重载为成员函数:若重载为成员函数:27. 5. operator + (x) / e

7、rrorLOGO208.2.3 其他运算符重载举例其他运算符重载举例v重载重载+和和运算符运算符 +和和-是单目运算符,分为前缀运算和后缀运算两种。是单目运算符,分为前缀运算和后缀运算两种。前缀前缀运算视为运算视为单目单目运算符,运算符,后缀后缀运算视为运算视为双目双目运算符。运算符。 函数类型函数类型 operator +( ); /前缀运算前缀运算 函数类型函数类型 operator -(int ); /后缀运算后缀运算 使用格式:使用格式: +对象对象 /前缀前缀 对象对象+ /后缀后缀 LOGO21举例:举例:#includeclass Testint n;public:Test(in

8、t i) n=i; void operator +() n+; void operator +(int) n+=2; void display() coutn=nendl; ;void main()Test t1(5),t2(5);t1+; /调用后缀重载运算符调用后缀重载运算符+t2; /调用前缀重载运算符调用前缀重载运算符t1.display();t2.display();运行结果:运行结果:n=7n=6LOGO22v重载重载+=和和-=运算符运算符 对于标准数据类型,对于标准数据类型,+=和和-=的作用是将一个数据的作用是将一个数据与另一个数据进行加法或减法运算,然后再将结果回送与另一个

9、数据进行加法或减法运算,然后再将结果回送给赋值号左边的变量中。对他们重载后,可以实现相关给赋值号左边的变量中。对他们重载后,可以实现相关的功能。的功能。LOGO23举例:举例:#includeclass Test int x,y;public: Test() Test(int i,int j) x=i;y=j; friend Test operator +=(Test t1,Test t2) t1.x+=t2.x; t1.y+=t2.y; return t1; Test operator -=(Test t) x=x-t.x; y=y-t.y; return *this; void displ

10、ay() cout(x,y)endl; ;void main() Test t1(6,8),t2(3,6); coutt1=; t1.display(); coutt2=; t2.display(); coutt1+t2=; (t1+=t2).display(); coutt1-t2=; (t1-=t2).display();LOGO24v重载下标运算符重载下标运算符 下标运算符下标运算符 通常用于获取数组的某个元素,重载通常用于获取数组的某个元素,重载下标运算符可以实现数组下标的下标运算符可以实现数组下标的越界检测越界检测等。下标运算等。下标运算符重载函数只能作为类的符重载函数只能作为类的成

11、员函数成员函数,不能作为类的友元,不能作为类的友元函数。函数。LOGO25#include#includeclass words int len;char *str;public:words(char *s) str=new charstrlen(s)+1; strcpy(str,s); len=strlen(s);char operator (int n) if(nlen-1) cout数组下标越界数组下标越界; return ; elsereturn *(str+n);void disp() coutstrendl; ;void main() words word(this is a C+

12、 book.); word.disp(); cout位置位置0:; coutword0endl; cout位置位置15:; coutword15endl; cout位置位置30:; coutword30endl;LOGO26v重载函数调用运算符重载函数调用运算符 函数调用运算符函数调用运算符()只能说明成类的非静态成员函数,只能说明成类的非静态成员函数,该函数具有以下的一般格式:该函数具有以下的一般格式: 数据类型数据类型 operator ( )(参数表参数表) const; 与普通函数一样,函数调用运算符可以带有与普通函数一样,函数调用运算符可以带有0个或个或多个参数,但不能带有缺省参数。

13、多个参数,但不能带有缺省参数。LOGO27例题:例题:#includeclass Fpublic:double operator ()(double x,double y) const;double F:operator ()(double x,double y) constreturn (x+5)*y;void main()F f;coutf(2.5,5)endl;LOGO28练习:练习:#includeclass Fpublic:double operator ()(double x,double y) constif(xy) return y;else return x;double o

14、perator ()(double x) constif(x0) return -x;else return x;void main()F f;coutf(1.5,2.3)endl;coutf(-1.5)endl;LOGO29v重载类型转换运算符重载类型转换运算符C+中提供了标准类型的相互转换,如执行语句:中提供了标准类型的相互转换,如执行语句: n=(int)1.87;则则n=1。同样,可以进行这种类型转换运算符重载。格式:。同样,可以进行这种类型转换运算符重载。格式: operator 类型名类型名( ) 函数体;函数体;LOGO30举例:实现人民币到美元的转换举例:实现人民币到美元的转换

15、#includeclass RMBdouble rmb;double rate;public:RMB() RMB(double x,double y) rmb=x;rate=y; operator double() return (rmb/rate); void setvalue() coutrmb; coutrate;void disp() cout人民币人民币:rmb元元(汇率汇率为为rate:1); ;void main() RMB a,b(1000,7.72); double m1,m2; a.setvalue(); m1=double(a); a.disp(); cout元元m1美元

16、美元endl; m2=double(b); b.disp(); cout元元m2美元美元endl;31例:指出程序中的错误,并改正。例:指出程序中的错误,并改正。class integerpublic: integer(int i=0) value=i; integer operator +(integer i) return integer(value+=i.value); private: int value;void main() integer i1=10; integer i2=i1+5; integer i3=3+i2;错误原因:3+i2等价于3.operator +(i2)32改

17、正改正:class integerpublic: integer(int i=0) value=i; friend integer operator +(integer i1,integer i2);private: int value;integer operator +(integer i1,integer i2) integer temp=i1.value+i2.value; return temp;33下面运算符能被重载的是下面运算符能被重载的是_。n:n?:n.n%34补充完整下面程序,结果为补充完整下面程序,结果为3 8。class Apublic:A(int aa,int bb)

18、a=aa;b=bb;void operator _(A &p)_;_;void show()coutab;private: int a,b;void main()A a1(2,5),a2(1,3);a1+=a2;a1.show();+=a=a+p.ab=b+p.b35n分别将取负运算符重载为友元函数和成员函数,分别将取负运算符重载为友元函数和成员函数,对复数求负。对复数求负。36#includeclass Testint real,imag;public:Test()Test(int i,int j)real=i;imag=j;Test operator -()real=-real;i

19、mag=-imag;return Test(real,imag);void display()cout(real,imag)endl;void main()Test t1(1,2),t2;t2=-t1;t2.display();LOGO37v思考:分别使用成员函数和友员函数编思考:分别使用成员函数和友员函数编程序重载运算符程序重载运算符“+”,使该运算符能实,使该运算符能实现两个字符串的连接。(可以使用现两个字符串的连接。(可以使用strcat函数)函数)LOGO38#include#includeclass stringchar str50;public:string(char s1)str

20、cpy(str,s1);string operator +(string s1)strcat(str,s1.str);return *this;void display()coutstrendl;void main()string s1(good),s2( morning);s1=s1+s2;s1.display();LOGO398.3 静态联编与动态联编静态联编与动态联编v联编联编 就是函数的入口地址同函数调用相联系的过程。就是函数的入口地址同函数调用相联系的过程。v静态联编(静态束定)静态联编(静态束定) 联编工作出现在联编工作出现在编译阶段编译阶段,在程序运行之前完成。由,在程序运行之前

21、完成。由编译系统或操作系统装入程序计算函数的入口地址。编译系统或操作系统装入程序计算函数的入口地址。v动态联编(动态束定)动态联编(动态束定) 联编工作在程序联编工作在程序运行运行时执行,由程序自身计算函数的时执行,由程序自身计算函数的入口地址,用入口地址,用虚函数虚函数来实现。来实现。LOGO40例例8.8 静态联编静态联编void fun(Point &s) coutArea=s.Area()endl; void main() Rectangle rec(3.0, 5.2, 15.0, 25.0); fun(rec);运行结果:运行结果:Area=0LOGO41#includecl

22、ass Point public:Point(double i, double j) x=i; y=j;virtual double Area( ) const return 0.0; private:double x, y;class Rectangle:public Point public:Rectangle(double i, double j, double k, double l):Point(i,j) w=k; h=l; virtual double Area( ) const return w*h; private:double w,h;例例8.9 动态联编动态联编void f

23、un(Point &s) coutArea=s.Area()endl; void main() Rectangle rec(3.0, 5.2, 15.0, 25.0); fun(rec);运行结果:运行结果:Area=375LOGO428.4 虚函数虚函数v由上例可知,虚函数是动态联编的基础。虚函由上例可知,虚函数是动态联编的基础。虚函数是非静态的成员函数。数是非静态的成员函数。定义格式virtual 类型说明符类型说明符 函数名函数名(参数表参数表)virtual 只用在类定义的原型说明中,不能用在函数实现中。只用在类定义的原型说明中,不能用在函数实现中。具有继承性,派生类中同原型函

24、数自动为虚函数。具有继承性,派生类中同原型函数自动为虚函数。用通过对象指针或对象引用来操作虚函数用通过对象指针或对象引用来操作虚函数LOGO43例题例题#include class B0 /基类基类B0声明声明public:virtual void display() /虚成员函数虚成员函数 coutB0:display()endl;class B1: public B0/公有派生公有派生 public:void display() /自动成为虚函数自动成为虚函数 coutB1:display()endl; ;class D1: public B1/公有派生公有派生 public: void

25、display() /自动成为虚函数自动成为虚函数 coutD1:display()display(); /通过指针调用虚函数通过指针调用虚函数void main() /主函数主函数B0 b0, *p; /声明基类对象和指针声明基类对象和指针B1 b1; /声明派生类对象声明派生类对象D1 d1; /声明派生类对象声明派生类对象p=&b0;fun(p); /调用基类调用基类B0函数成员函数成员p=&b1;fun(p); /调用派生类调用派生类B1函数成员函数成员p=&d1;fun(p); /调用派生类调用派生类D1函数成员函数成员运行结果运行结果B0:display()

26、B1:display()D1:display()LOGO45v构造函数中调用虚函数,静态联编,即构造函数调用构造函数中调用虚函数,静态联编,即构造函数调用的虚函数是自己类中实现的虚函数。如果自己类中没有的虚函数是自己类中实现的虚函数。如果自己类中没有实现这个虚函数,则调用从基类中继承的虚函数。实现这个虚函数,则调用从基类中继承的虚函数。LOGO46例:构造函数调用虚函数例:构造函数调用虚函数#includeclass Apublic:A()virtual void f() coutA:f() called.n; ;class B:public Apublic:B()f();void g()f(

27、);class C:public Bpublic:C()virtual void f() coutC:f() called.n; ;void main()C c;c.g();LOGO47v析构函数中调用虚函数同构造函数一样,即析构析构函数中调用虚函数同构造函数一样,即析构函数所调用的虚函数是在自身类中或基类中实现的函数所调用的虚函数是在自身类中或基类中实现的虚函数。虚函数。LOGO488.6 虚析构函数虚析构函数v用用delete语句调用析构函数释放对象,希望自动根据语句调用析构函数释放对象,希望自动根据对象指针的类型调用对象指针的类型调用相对应相对应的析构函数,但若析构函数的析构函数,但若析

28、构函数本身不具有虚函数的性质,则没有达到动态联编的效果。本身不具有虚函数的性质,则没有达到动态联编的效果。因此,需将析构函数定义为虚函数。因此,需将析构函数定义为虚函数。可以声明虚析可以声明虚析构函数,构函数,但不但不能声明虚构造能声明虚构造函数。函数。注意:注意:LOGO49一般将所有继承类中一般将所有继承类中最基类的析构函数最基类的析构函数设置为虚析构函数。设置为虚析构函数。如果一个如果一个基类基类的析构函数是虚函数,那么由它派生的的析构函数是虚函数,那么由它派生的子类子类的析构函数也是虚函数的析构函数也是虚函数LOGO50void fun(A *a) delete a;void main

29、() A *a=new B(15); fun(a);#includeclass A public: virtual A() coutA:A()called.n;class B:public Apublic: B(int i)buf=new chari; virtual B() delete buf; coutB:B() called.n; private: char *buf;LOGO51 以下程序的功能是:利用友员函数为类的成员变量进行初始化,然后利用成员函数输出。请改正程序中的错误,使之能正确运行。#includeclass A int a,b; public: friend void s

30、etval(int i,int j); void showA() couta,bendl; ;void setval(int i,int j)a=i; b=j;void main()A obj1; setval(2,3); obj1.showA();LOGO528.5 纯虚函数和抽象类纯虚函数和抽象类问题问题: 基类中的虚函数经常不可能被调用,这时可基类中的虚函数经常不可能被调用,这时可以定义该虚函数为以定义该虚函数为纯虚函数纯虚函数。纯虚函数没有函数。纯虚函数没有函数体,在派生类中实现。体,在派生类中实现。LOGO53纯虚函数纯虚函数v纯虚函数的声明格式:纯虚函数的声明格式: virtual

31、 函数类型函数类型 函数名函数名(参数表参数表) = 0 ;v注意区分注意区分函数体为空的虚函数函数体为空的虚函数与与纯虚函数纯虚函数的区别。的区别。LOGO54#includeclass pointpublic: point(int i=0,int j=0) x0=i;y0=j; virtual void set()=0; virtual void draw()=0;protected: int x0,y0;class line:public pointpublic: line(int i=0,int j=0,int m=0,int n=0) :point(i,j) x1=m;y1=n; void set() coutline:set() called.n; void draw() coutline:draw() called.n; protected: int x1,y1;class ellipse:public point public

温馨提示

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

评论

0/150

提交评论