欢迎来到三一文库! | 帮助中心 三一文库31doc.com 一个上传文档投稿赚钱的网站
三一文库
全部分类
  • 研究报告>
  • 工作总结>
  • 合同范本>
  • 心得体会>
  • 工作报告>
  • 党团相关>
  • 幼儿/小学教育>
  • 高等教育>
  • 经济/贸易/财会>
  • 建筑/环境>
  • 金融/证券>
  • 医学/心理学>
  • ImageVerifierCode 换一换
    首页 三一文库 > 资源分类 > PPT文档下载  

    西安工业大学耿军雪老师的C课件之多态性.ppt

    • 资源ID:2095685       资源大小:692.51KB        全文页数:95页
    • 资源格式: PPT        下载积分:8
    快捷下载 游客一键下载
    会员登录下载
    微信登录下载
    三方登录下载: 微信开放平台登录 QQ登录   微博登录  
    二维码
    微信扫一扫登录
    下载资源需要8
    邮箱/手机:
    温馨提示:
    用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)
    支付方式: 支付宝    微信支付   
    验证码:   换一换

    加入VIP免费专享
     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    西安工业大学耿军雪老师的C课件之多态性.ppt

    Object Oriented,面向对象技术与C+,计算机学院,Object Oriented,5-0 分析结果?,#include class point double x,y; public : point (double i,double j) x=i;y=j; double area() return 0.0; ; class rectangle : public point double w,h; public : rectangle(double i,double j,double m,double n):point(i,j) w=m;h=n; double area() return w*h; ; void fun(point ,Object Oriented,第五章 多态性,本章主要内容: 多态性 同一名称,不同的功能实现方式 运算符重载 多态的经典内容 虚函数 动态绑定 纯虚函数 统一接口 抽象类 定义一个框架,由其衍生对象完善,Object Oriented,一、多态性 多态性:是指不同对象在收到相同的消息时,产生不同的动作用同一个名字定义不同的函数,执行不同但相似的操作实现“一个接口,多种方法”。 多态的实现: 函数重载:通过形参来区分 运算符重载:只是一种“语法修饰”,是专用格式的函数重载 虚函数:冠以关键字 virtual 的成员函数称为虚函数,Object Oriented,二、联编的概念及分类 1、联编的概念 联编:源程序经过编译、联接成可执行文件的过程 即将可执行代码联编(装配)在一起的过程。 2、联编的分类: 静态联编(前期联编):在运行前完成的联编在编译时完成(要求在编译时就知道调用函数的全部信息)其优点是“效率高”。(重载函数使用静态联编。) 动态联编(后期联编):在运行时才完成的联编在程序运行时动态调用所需函数优点是提供了更好的“灵活性”、问题的“抽象性”、程序的“易维护性”。(switch 语句和 if 语句是动态联编的例子),Object Oriented,三、多态性的分类 编译时多态性:静态联编支持的多态性(静态多态性)通过函数重载及运算符重载实现。 运行时多态性:动态联编支持的多态性(动态多态性)通过虚函数实现。 四、函数重载 同一个类中的同名函数参数个数不一样、参数类型不一样、参数个数及类型不一样; 不同类中的同名函数通过类名调用或类的对象调用。 同一个类中同名的普通成员函数及常量成员函数通过const实现重载。,Object Oriented,第一节 虚函数和基类指针,冠以关键字 virtual 的成员函数称为虚函数 实现运行时多态的关键首先是要说明虚函数,另外,必须用基类指针调用派生类的不同实现版本 虚函数与派生类相结合,使C+能支持运行时多态性实现在基类中定义派生类所拥有的通用“接口”,而在派生类中定义具体的实现方法,即“一个接口,多种方法”。,Object Oriented,5-1,#include class Base public : Base(char xx) x = xx; void who() cout “Base class: “ x “n“ ; protected: char x; ; class First_d : public Base public : First_d(char xx, char yy):Base(xx) y = yy; void who() cout “First derived class: “ x “, “ y “n“ ; protected: char y; ; class Second_d : public First_d public : Second_d( char xx, char yy, char zz ) : First_d( xx, yy ) z = zz; void who() cout “Second derived class: “ x “, “ y “, “ z “n“ ; protected: char z; ;,Object Oriented,void main() Base B_obj( 'A' ) ; First_d F_obj( 'T', 'O' ) ; Second_d S_obj( 'E', 'N', 'D' ) ; Base * p ; p = ,通过基类指针 只能访问从基类继承的成员,Object Oriented,5-2,#include class Base public : Base(char xx) x = xx; virtual void who() cout “Base class: “ x “n“ ; protected: char x; ; class First_d : public Base public : First_d(char xx, char yy):Base(xx) y = yy; void who() cout “First derived class: “ x “, “ y “n“ ; protected: char y; ; class Second_d : public First_d public : Second_d( char xx, char yy, char zz ) : First_d( xx, yy ) z = zz; void who() cout“Second derived class: “x“, “y“, “z“n“ ; protected: char z; ;,Object Oriented,void main() Base B_obj( 'A' ) ; First_d F_obj( 'T', 'O' ) ; Second_d S_obj( 'E', 'N', 'D' ) ; Base * p ; p = ,由于who()的虚特性 随着p指向不同对象,执行不同实现版本,Object Oriented,注意: 一个虚函数,在派生类层界面相同的重载函数都保持虚特性 虚函数必须是类的成员函数,不能是全局函数和静态函数 不能将友员说明为虚函数,但虚函数可以是另一个类的友员 析构函数可以是虚函数,但构造函数不能是虚函数 动态联编只能通过指针或引用来操作虚函数,如果采用其他标识对象来操作虚函数,将采用静态联编方式调用虚函数。,Object Oriented,虚析构函数,构造函数不能是虚函数。建立一个派生类对象时,必须从类层次的根开始,沿着继承路径逐个调用基类的构造函数 析构函数可以是虚的。虚析构函数用于指引 delete 运算符正确析构动态对象,Object Oriented,5-3普通析构函数在删除动态派生类对象的调用情况,#include class A public: A() cout “A:A() is called.n“ ; ; class B : public A public: B() cout “B:B() is called.n“ ; ; void main() A *Ap = new B ;/用基类指针建立派生类的动态对象 B *Bp2 = new B ;/用派生类指针建立派生类的动态对象 cout “delete first object:n“ ; delete Ap;/析构由基类指针建立的派生类对象没有调用派生类构造函数问题? cout “delete second object:n“ ; delete Bp2 ;/析构由派生类指针建立的派生类对象正确调用派生类构造函数 ,Object Oriented,5-4虚析构函数在删除动态派生类对象的调用情况,#include class A public: virtual A() cout “A:A() is called.n“ ; ; class B : public A public: B() cout “B:B() is called.n“ ; ; void main() A *Ap = new B ; B *Bp2 = new B ; cout “delete first object:n“ ; delete Ap; cout “delete second object:n“ ; delete Bp2 ; ,定义了基类虚析构函数,基类指针指向的 派生类动态对象也可以正确地用delete析构 设计类层次结构时,提供一个虚析构函数, 能够使派生类对象在不同状态下正确调用析构函数,Object Oriented,第二节 纯虚函数和抽象类,纯虚函数是一个在基类中说明的虚函数,为各派生类提供一个公共界面,在基类中没有定义,要求任何派生类都定义自己的版本 纯虚函数 纯虚函数说明形式: virtual 类型 函数名(参数表)= 0 ; 一个具有纯虚函数的基类称为抽象类。,Object Oriented,class figure /figure.h protected : double x,y; 5-5 public: void set_dim(double i, double j=0) x = i ; y = j ; virtual void show_area() = 0 ; ; class triangle : public figure public : void show_area() cout“Triangle with high “x“ and base “y “ has an area of “x*0.5*y“n“; ; class square : public figure public: void show_area() cout“Square with dimension “x“*“y “ has an area of “x*y“n“; ; class circle : public figure public: void show_area() cout“Circle with radius “x; cout“ has an area of “3.14*x*x“n“; ;,Object Oriented,#include #include“figure.h“ void main() triangle t ; /派生类对象 square s ; circle c; t.set_dim(10.0,5.0) ; t.show_area(); s.set_dim(10.0,5.0) ; s.show_area() ; c.set_dim(9.0) ; c.show_area() ; ,抽象类至少有一个纯虚函数。 如果抽象类的一个派生类没有为继承的纯虚函数定义实现版本,则它仍然是抽象类。,Object Oriented,5-6,class point /*/ ; class shape ; / 抽象类 point center ; public : point where ( ) return center ; void move ( point p ) enter = p ; draw ( ) ; virtual void rotate ( int ) = 0 ; / 纯虚函数 virtual void draw ( ) = 0 ; / 纯虚函数 ; .,shape x ; / error,抽象类不能建立对象 shape *p ; / ok,可以声明抽象类的指针 shape f ( ) ; / error, 抽象类不能作为返回类型 void g ( shape ) ; / error, 抽象类不能作为参数类型 shape / ok,可以声明抽象类的引用,Object Oriented,class ab_circle : public shape int radius ; public : void rotate ( int ) ; ;,ab_circle 类仍为抽象类 ab_circle : draw ( ) 、ab_circle : rotate ( ) 也是纯虚函数,要使 ab_circle 成为非抽象类, 必须作以下说明: class ab_circle : public shape int radius ; public : void rotate ( int ) ; void draw ( ) ; ; 并提供 ab_circle : draw ( ) 和 ab_circle : rotate ( int ) 的定义,Object Oriented,5-7声明抽象类指针,#include #include“figure.h“ void main() figure *p; / 声明抽象类指针 triangle t; square s; circle c; p= ,Object Oriented,5-8抽象类引用,#include class Number public : Number (int i) val = i ; virtual void Show() = 0 ; protected: int val ; ; class Hex_type : public Number public: Hex_type(int i) : Number(i) void Show() cout “Hexadecimal:“ hex val endl ; ; class Dec_type : public Number public: Dec_type(int i) : Number(i) void Show() cout “Decimal: “ dec val endl ; ; class Oct_type : public Number public: Oct_type(int i) : Number(i) void Show() cout “Octal: “ oct val endl ; ;,Object Oriented,void fun( Number / Oct_type:Show() ,Object Oriented,应用举例求圆、圆的内切正方形及外切正方形的面积及周长 #include #include class shape protected : double r; public: shape(double x) r=x; virtual double area()=0; virtual double perimeter()=0; ;,Object Oriented,class circle:public shape public: circle(double x):shape(x) double area() return 3.14*r*r; double perimeter() return 2*3.14*r; ; class in_square:public shape public: in_square(double x):shape(x) double area() return 2*r*r; double perimeter() return 4*sqrt(2)*r; ;,Object Oriented,class ex_square:public shape public: ex_square(double x):shape(x) double area() return 4*r*r; double perimeter() return 8*r; ; void main() shape *p; circle ob1(5.0); in_square ob2(5.0); ex_square ob3(5); p=,Object Oriented,第三节 运算符重载,运算符重载使得用户自定义的数据以一种更简洁的方式工作,就是赋予已有的运算符多重含义。,例如 int x , y ; y = x + y ;,matrix m1 , m2 ; / 矩阵类对象 m2 = Madd ( m1 , m2 ) ; / 调用函数计算两个矩阵的和,complex c1 , c2 ; / 复数类对象 c1 = Cadd (c1 , c2 ) ; / 调用函数计算两个复数的和,能表示为 c1 = c1 + c2 ; ?,能表示为 m1 = m1 + m2 ; ?,定义 运算符重载函数,Object Oriented,类以外的运算符重载,#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; total1=operator+(com1,com2);/运算符重载的使用方法1 cout “real1=“total1.real; cout“ imag1=“total1.imagendl; total2=com1+com2;/运算符重载的使用方法2 cout “real2=“total2.real; cout“ imag2=“total2.imagendl; ,Object Oriented,一、运算符重载的实质 运算符重载是对已有的运算符赋予多重含义 必要性 C+中预定义的运算符其运算对象只能是基本数据类型,而不适用于用户自定义类型(如类) 实现机制 将指定的运算表达式转化为对运算符函数的调用,运算对象转化为运算符函数的实参。 相当于a+b = +(a,b) 编译系统对重载运算符的选择,遵循函数重载的选择原则。 相当于选+(1,2)还是+(1,1),(2,2)?,Object Oriented,二、重载运算符的限制 1、不能重载的算符 . : * ?: # sizeof 2、重载运算符可以对运算符作出新的解释,但原有基本语义不变: 不改变运算符的优先级和结合性。(否则难以记忆) 不改变运算符所需要的操作数,即单目运算符只能重载为单目运算符,不能将单目运算符重载为双目运算符。 不能创建新的运算符,只有系统预定义的运算符才能被重载。 经重载的运算符,其操作数中至少应该有一个是自定义类型。 (否则系统已经实现了) 3、运算符通常是对类中的私有成员进行操作,故重载运算符应能访问类中的私有成员,所以重载运算符一般采用成员函数或友员函数的形式,Object Oriented,三、重载为类成员函数 语法形式为: 类型 类名 : operator op ( 参数表 ) / 相对于该类定义的操作 其中,当为双目运算符时,参数表中为一个参数,单目运算符时,参数表为空通过this指针传递。,Object Oriented,(一)双目运算符的重载 例【5.3.2】重载二个复数对象的加、减、乘、除运算符熟悉双目运算符的重载。 1、分析:设两个复数a+bi和c+di,则有: 加法:(a+bi)+(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)/(c2+d2) =(ac+bd)/ (c2+d2)+(bc-ad)i/(c2+d2) 2、程序:,Object Oriented,#include class complex private : double real ; double imag; public : complex(double r=0,double i=0) real=r;imag=i; complex operator+(complex c); complex operator-(complex c); complex operator*(complex c); complex operator/(complex c); void print(); ;,Object Oriented,complex complex :operator+(complex c)/重载“+” complex temp; temp.real=real+c.real; temp.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; ,Object Oriented,complex complex :operator*(complex c)/重载“*” complex temp; temp.real=real*c.real-imag*c.imag; temp.imag=real*c.imag+imag*c.real; return temp; complex complex :operator/(complex c)/重载“/” complex temp; double t; t=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; ,Object Oriented,void complex:print() cout 0) cout“+“; if (imag!=0) cout imag“i“endl; void main() 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();A2.print(); A3.print();A4.print(); A5.print();A6.print(); ,Object Oriented,(二)单目运算符重载(单目运算符重载时没有参数。) 前置和后置,函数名都是operator +,所以人为给后置多加一个哑参数,只有类型名。 例【5.3.3】运算符前置+和后置+重载为时钟类的成员函数。 前置单目运算符,重载函数没有形参,对于后置单目运算符,重载函数需要有一个整型形参。 操作数是时钟类的对象。 实现时间增加1秒钟。,Object Oriented,#include class Clock /时钟类声明 public: /外部接口 Clock(int NewH=0, int NewM=0, int NewS=0) Hour=NewH;Minute=NewM;Second=NewS; void ShowTime() coutHour“:“Minute“:“Secondendl; void operator +(); /前置单目运算符重载 void operator +(int); /后置单目运算符重载 private: /私有数据成员 int Hour, Minute, Second; ;,Object Oriented,void Clock:operator +( ) /前置单目运算符重载函数 Second+; if(Second=60) /考虑进位 Second=Second-60; Minute+; if(Minute=60) Minute=Minute-60; Hour+; Hour=Hour%24; cout“+Clock: “; ,Object Oriented,void Clock:operator +(int) /后置单目运算符重载 Second+; if(Second=60) Second=Second-60; Minute+; if(Minute=60) Minute=Minute-60; Hour+; Hour=Hour%24; cout“Clock+: “; ,Object Oriented,void main() Clock myClock(23,59,59); cout“First time output:“; myClock.ShowTime(); myClock+; myClock.ShowTime(); +myClock; myClock.ShowTime(); ,Object Oriented,四、重载为友元函数 例【5.3.4】将+、-(双目)重载为复数类的友元函数。 两个操作数都是复数类的对象。 #include class complex private : double real ; double imag; public : complex(double r=0,double i=0) real=r;imag=i; void print(); friend complex operator+(complex a,complex b); friend complex operator-(complex a,complex b); friend complex operator*(complex a,complex b); friend complex operator/(complex a,complex b); ;,Object Oriented,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; temp.imag=a.imag-b.imag; return temp; ,Object Oriented,complex operator*(complex a,complex b) complex temp; temp.real=a.real*b.real-a.imag*b.imag; temp.imag=a.real*b.imag+a.imag*b.real; return temp; complex operator/(complex a,complex b) complex temp; double t; t=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; ,Object Oriented,void complex:print() cout 0) cout“+“; if (imag!=0) cout imag“i“endl; void main() 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(); A2.print(); A3.print(); A4.print(); A5.print(); A6.print(); ,Object Oriented,重载为成员函数,解释为: Object . operator op () 操作数由对象Object通过this指针隐含传递 重载为友员函数,解释为: operator op (Object) 操作数由参数表的参数Object提供,1一元运算符,Object op 或 op Object,Object Oriented,重载为成员函数,解释为: ObjectL . operator op ( ObjectR ) 左操作数由ObjectL通过this指针传递,右操作数由参数ObjectR传递 重载为友员函数,解释为: operator op ( ObjectL, ObjectR ) 左右操作数都由参数传递,2二元运算符,ObjectL op ObjectR,Object Oriented,总结 运算符函数可以重载为成员函数或友员函数 关键区别在于成员函数具有 this 指针,友员函数没有this指针 不管是成员函数还是友员函数重载,运算符的使用方法相同。但传递参数的方法不同,实现代码不同,应用场合也不同。 当一元运算符的操作数,或者二元运算符的左操作数是该类的一个对象时,定义重载运算符函数为成员函数 友员函数重载运算符常用于算符的左右操作数类型不同的情况,左操作数可以是常数或其他类型的数。 运算符=、( )、 、-不能用友元函数重载,(只能用成员函数重载),Object Oriented,class nclass private : int a ; int b ; public : nclass operator+(int x); ; nclass nclass : operator+(int x) nclass temp ; temp.a=a+x; temp.b=b+x; return temp; ,void main() nclass ob1,ob2; ob2=ob1+100; ob2=100+ob1; ,程序中: ob2=ob1+100;正确 ob2=100+ob1;不正确,为什么?,Object Oriented,例【5.3.5】常数与复数相加。 #include class complex private : double real ; double imag; public : complex(double r=0,double i=0) real=r;imag=i; void show() cout “real=“real“ imag=“imagendl; friend complex operator+(complex co,double x); friend complex operator+(double x,complex co); ;,Object Oriented,complex operator+(complex co,double x) complex temp; temp.real=co.real+x; temp.imag=co.imag; return temp; complex operator+(double x,complex co) complex temp; temp.real=x+co.real; temp.imag=co.imag; return temp; void main() complex com1(1.1,2.2),com2,com3; com2=com1+10.0; com2.show(); com3=20.0+com1; com3.show(); ,Object Oriented,五、赋值运算符“=”的重载 同拷贝构造函数一样,通常“=”不用重载,同一类的对象可直接赋值。如:ob1=ob2; 当在类中用new分配内存空间,在析构函数中用delete中释放内存空间时,应重载“=”运算符。,例【5.3.6】调试下列程序,分析出错的原因,#include #include class string char *ptr; public : string(char *s) ptr=new charstrlen(s)+1; strcpy(ptr,s); string() delete ptr; void print() cout ptrendl; ;,void main() string p1(“chen“); string p2(“ “); p2=p1; cout “p2: “; p2.print(); cout“p1: “; p1.print(); ,Object Oriented,void main() string p1(“chen“); string p2(“ “); p2=p1; cout “p2: “; p2.print(); cout“p1: “; p1.print(); ,Object Oriented,出错原因分析:,Object Oriented,解决办法:重载“=”运算符 例【5.3.7】将上例程序改为:,#include #include class string char *ptr; public : string(char *s) ptr=new charstrlen(s)+1; strcpy(ptr,s); string() delete ptr; void print() cout ptrendl; string ,Object Oriented,string ,说明: 类的赋值运算符“=”只能重载为成员函数,重载后不能被继承。,Object Oriented,注意:对象初始化时的赋值和已创建对象之间的赋值虽然都涉及对象的复制,但它们是两个不同的操作。对象初始化首先是为新对象分配存储空间,然后执行对象复制。 如:Point p1, p2(3.14, 4.06); Point p3=p2; /调用拷贝构造初始化函数 p1=p2; /调用赋值运算符重载,Object Oriented,本章小结,多态: 同样的消息被不同类型的对象接收时导致完全不同的行为,是对类的特定成员函数的再抽象。 运算符重载 对已有的运算符赋予多重含义,使用已有运算符对用户自定义类型(比如类)进行运算操作。 联编 程序自身彼此关联的过程称为联编,联编确定程序中的操作调用与执行该操作的代码间的关系。 静态联编工作出现在编译阶段。 动态联编工作在程序运行时执

    注意事项

    本文(西安工业大学耿军雪老师的C课件之多态性.ppt)为本站会员(本田雅阁)主动上传,三一文库仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知三一文库(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    经营许可证编号:宁ICP备18001539号-1

    三一文库
    收起
    展开