欢迎来到三一办公! | 帮助中心 三一办公31ppt.com(应用文档模板下载平台)
三一办公
全部分类
  • 办公文档>
  • PPT模板>
  • 建筑/施工/环境>
  • 毕业设计>
  • 工程图纸>
  • 教育教学>
  • 素材源码>
  • 生活休闲>
  • 临时分类>
  • ImageVerifierCode 换一换
    首页 三一办公 > 资源分类 > PPT文档下载  

    C++语言程序设计(清华大学郑莉)八ppt课件.ppt

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

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

    C++语言程序设计(清华大学郑莉)八ppt课件.ppt

    1,第八章 多态性,清华大学 郑 莉,C+语言程序设计,2,本章主要内容,多态性运算符重载虚函数纯虚函数抽象类深度探索,3,多态性的概念,多态性是面向对象程序设计的重要特征之一。多态性是指发出同样的消息被不同类型的对象接收时有可能导致完全不同的行为。多态的实现:函数重载运算符重载虚函数,4,问题举例复数的运算,class Complex /复数类声明public:Complex(double r = 0.0,double i = 0.0) real = r; imag=i; void display() const;/显示复数的值private:double real;double imag;,运算符重载,5,问题举例复数的运算,用“+”、“-”能够实现复数的加减运算吗?实现复数加减运算的方法 重载“+”、“-”运算符,运算符重载,6,运算符重载的实质,运算符重载是对已有的运算符赋予多重含义必要性C+中预定义的运算符其运算对象只能是基本数据类型,而不适用于用户自定义类型(如类)实现机制将指定的运算表达式转化为对运算符函数的调用,运算对象转化为运算符函数的实参。编译系统对重载运算符的选择,遵循函数重载的选择原则。,运算符重载,7,运算符重载,规则和限制,可以重载C+中除下列运算符外的所有运算符:. .* : ?:只能重载C+语言中已有的运算符,不可臆造新的。不改变原运算符的优先级和结合性。不能改变操作数个数。经重载的运算符,其操作数中至少应该有一个是自定义类型。,8,两种形式,重载为类的非静态成员函数重载为非成员函数,运算符重载,9,运算符函数,声明形式函数类型 operator 运算符(形参) .重载为类成员函数时 参数个数=原操作数个数-1(后置+、-除外)重载为非成员函数时 参数个数=原操作数个数,且至少应该有一个自定义类型的形参。,运算符重载,10,运算符成员函数的设计,双目运算符 B如果要重载 B 为类成员函数,使之能够实现表达式 oprd1 B oprd2,其中 oprd1 为A 类对象,则 B 应被重载为 A 类的成员函数,形参类型应该是 oprd2 所属的类型。经重载后,表达式 oprd1 B oprd2 相当于 oprd1.operator B(oprd2),运算符重载,11,运算符重载,例 8-1,将“+”、“-”运算重载为复数类的成员函数。 规则:实部和虚部分别相加减。 操作数:两个操作数都是复数类的对象。,#include using namespace std;class Complex /复数类定义public:/外部接口Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) /构造函数Complex operator + (const Complex ,12,Complex Complex:operator + (const Complex /创建一个临时无名对象作为返回值,13,void Complex:display() const cout ( real , imag ) endl;int main() /主函数Complex c1(5, 4), c2(2, 10), c3;/定义复数类的对象cout c1 = ; c1.display();cout c2 = ; c2.display();c3 = c1 - c2;/使用重载运算符完成复数减法cout c3 = c1 - c2 = ; c3.display();c3 = c1 + c2;/使用重载运算符完成复数加法cout c3 = c1 + c2 = ; c3.display();return 0;,14,程序输出的结果为:c1 = (5, 4)c2 = (2, 10)c3 = c1 - c2 = (3, -6)c3 = c1 + c2 = (7, 14),15,16,运算符成员函数的设计,前置单目运算符 U如果要重载 U 为类成员函数,使之能够实现表达式 U oprd,其中 oprd 为A类对象,则 U 应被重载为 A 类的成员函数,无形参。经重载后,表达式 U oprd 相当于 oprd.operator U(),运算符重载,17,运算符成员函数的设计,后置单目运算符 +和-如果要重载 +或-为类成员函数,使之能够实现表达式 oprd+ 或 oprd- ,其中 oprd 为A类对象,则 +或- 应被重载为 A 类的成员函数,且具有一个 int 类型形参。经重载后,表达式 oprd+ 相当于 oprd.operator +(0),运算符重载,18,例8-2,运算符前置+和后置+重载为时钟类的成员函数。前置单目运算符,重载函数没有形参,对于后置单目运算符,重载函数需要有一个整型形参。操作数是时钟类的对象。实现时间增加1秒钟。,运算符重载,#include using namespace std;class Clock /时钟类声明定义public:/外部接口Clock(int hour = 0, int minute = 0, int second = 0);void showTime() const;Clock,19,/前置单目运算符重载函数Clock ,20,/后置单目运算符重载Clock Clock:operator + (int) /注意形参表中的整型参数Clock old = *this;+(*this);/调用前置“+”运算符return old;,21,/其它成员函数的实现略int main() Clock myClock(23, 59, 59);cout First time output: ;myClock.showTime();cout Show myClock+: ;(myClock+).showTime();cout Show +myClock: ;(+myClock).showTime();return 0;,22,程序运行结果为:First time output: 23:59:59Show myClock+: 23:59:59Show +myClock: 0:0:1,23,24,运算符非成员函数的设计,函数的形参代表依自左至右次序排列的各操作数。后置单目运算符 +和-的重载函数,形参列表中要增加一个int,但不必写形参名。如果在运算符的重载函数中需要操作某类对象的私有成员,可以将此函数声明为该类的友元。,运算符重载,25,运算符非成员函数的设计,双目运算符 B重载后,表达式oprd1 B oprd2 等同于operator B(oprd1,oprd2 )前置单目运算符 B重载后,表达式 B oprd 等同于operator B(oprd )后置单目运算符 +和-重载后,表达式 oprd B 等同于operator B(oprd,0 ),运算符重载,26,例8-3,将+、-(双目)重载为非成员函数,并将其声明为复数类的友元,两个操作数都是复数类的常引用。将(双目)重载为非成员函数,并将其声明为复数类的友元,它的左操作数是std:ostream引用,右操作数为复数类的常引用,返回std:ostream引用,用以支持下面形式的输出:cout a b;该输出调用的是:operator (operator (cout, a), b);,运算符重载,#include using namespace std;class Complex /复数类定义public:/外部接口Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) /构造函数friend Complex operator + (const Complex ,27,Complex operator + (const Complex ,28,29,静态绑定与动态绑定,绑定程序自身彼此关联的过程,确定程序中的操作调用与执行该操作的代码间的关系。静态绑定绑定过程出现在编译阶段,用对象名或者类名来限定要调用的函数。动态绑定绑定过程工作在程序运行时执行,在程序运行时才确定将要调用的函数。,#includeusing namespace std;class Point public:Point(double x, double y) : x(x), y(y) double area() const return 0.0; private:double x, y;class Rectangle: public Point public:Rectangle(double x, double y, double w, double h);double area() const return w * h; private:double w, h;,静态绑定例,30,Rectangle:Rectangle(double x, double y, double w, double h) :Point(x, y), w(w), h(h) void fun(const Point 运行结果:Area = 0,31,#includeusing namespace std;class Point public:Point(double x, double y) : x(x), y(y) virtual double area() const return 0.0; private:double x, y;class Rectangle:public Point public:Rectangle(double x, double y, double w, double h);virtual double area() const return w * h; private:double w, h;/其他函数同上例,动态绑定例,32,void fun(const Point 运行结果:Area = 375,33,34,虚函数,虚函数是动态绑定的基础。是非静态的成员函数。在类的声明中,在函数原型之前写virtual。virtual 只用来说明类声明中的原型,不能用在函数实现时。具有继承性,基类中声明了虚函数,派生类中无论是否说明,同原型函数都自动为虚函数。本质:不是重载声明而是覆盖。调用方式:通过基类指针或引用,执行时会根据指针指向的对象的类,决定调用哪个函数。,虚 函 数,35,例 8-4,#include using namespace std;class Base1 /基类Base1定义public:virtual void display() const;/虚函数;void Base1:display() const cout Base1:display() endl;class Base2: public Base1 /公有派生类Base2定义public:void display() const;/覆盖基类的虚函数;void Base2:display() const cout Base2:display() endl;,虚 函 数,/公有派生类Derived定义class Derived: public Base2 public:void display() const; /覆盖基类的虚函数;void Derived:display() const cout display();/对象指针-成员名,36,int main() /主函数Base1 base1;/定义Base1类对象Base2 base2;/定义Base2类对象Derived derived;/定义Derived类对象fun(,运行结果:Base1:display()Base2:display()Derived:display(),37,38,虚析构函数,为什么需要虚析构函数?可能通过基类指针删除派生类对象;如果你打算允许其他人通过基类指针调用对象的析构函数(通过delete这样做是正常的),就需要让基类的析构函数成为虚函数,否则执行delete的结果是不确定的。,虚 函 数,39,抽象类,带有纯虚函数的类称为抽象类:class 类名 virtual 类型 函数名(参数表)=0; /纯虚函数 .,纯虚函数与抽象类,40,抽象类,纯虚函数与抽象类,作用抽象类为抽象和设计的目的而声明,将有关的数据和行为组织在一个继承层次结构中,保证派生类具有要求的行为。对于暂时无法实现的函数,可以声明为纯虚函数,留给派生类去实现。注意抽象类只能作为基类来使用。不能声明抽象类的对象。构造函数不能是虚函数,析构函数可以是虚函数。,41,例 8-5,纯虚函数与抽象类,#include using namespace std;class Base1 /基类Base1定义public:virtual void display() const = 0;/纯虚函数;class Base2: public Base1 /公有派生类Base2定义public:void display() const /覆盖基类的虚函数cout Base2:display() endl;class Derived: public Base2 /公有派生类Derived定义public:void display() const /覆盖基类的虚函数cout Derived:display() endl;,void fun(Base1 *ptr) ptr-display();/对象指针-成员名int main() /主函数Base2 base2;/定义Base2类对象Derived derived;/定义Derived类对象fun(,运行结果:Base2:display()Derived:display(),42,多态类型与非多态类型,多态类型与非多态类型有虚函数的类类型称为多态类型其它类型皆为非多态类型二者的差异语言层面的差异多态类型支持运行时类型识别多态类型对象占用额外的空间设计原则上的差异,43,深 度 探 索,设计原则,多态类型多态类型的析构函数一般应为虚函数非多态类型非多态类型不宜作为公共基类由于没有利用动态多态性,一般可以用组合,而无需用共有继承;如果继承,则由于析构函数不是虚函数,删除对象时所执行操作与指针类型有关,易引起混乱。把不需被继承的类型设定为非多态类型由于成员函数都是静态绑定,调用速度较快;对象占用空间较小。,44,深 度 探 索,运行时类型识别,运行时类型识别允许在运行时通过基类指针(或引用)辨别对象所属的具体派生类;只对多态类型适用;比虚函数动态绑定的开销更大,因此应仅对虚函数无法解决的问题使用。运行时类型识别的方式用dynamic_cast做类型转换的尝试;用typeid直接获取类型信息。,45,深 度 探 索,dynamic_cast的使用,语法形式dynamic_cast(表达式)功能将基类指针转换为派生类指针,将基类引用转换为派生类引用;转换是有条件的如果指针(或引用)所指对象的实际类型与转换的目的类型兼容,则转换成功进行;否则如执行的是指针类型的转换,则得到空指针;如执行的是引用类型的转换,则抛出异常。,46,深 度 探 索,例8-9 dynamic_cast示例,#include using namespace std;class Base public:virtual void fun1() cout Base:fun1() endl; virtual Base() ;class Derived1: public Base public:virtual void fun1() cout Derived1:fun1() endl; virtual void fun2() cout Derived1:fun2() endl; ;class Derived2: public Derived1 public:virtual void fun1() cout Derived2:fun1() endl; virtual void fun2() cout Derived2:fun2() endl; ;,47,深 度 探 索,void fun(Base *b) b-fun1();/尝试将b转换为Derived1指针Derived1 *d = dynamic_cast(b);/判断转换是否成功if (d != 0) d-fun2();int main() Base b;fun(,运行结果:Base:fun1()Derived1:fun1()Derived1:fun2()Derived2:fun1()Derived2:fun2(),48,typeid的使用,语法形式typeid ( 表达式 )typeid ( 类型说明符 )功能获得表达式或类型说明符的类型信息表达式有多态类型时,会被求值,并得到动态类型信息;否则,表达式不被求值,只能得到静态的类型信息。类型信息用type_info对象表示type_info是typeinfo头文件中声明的类;typeid的结果是type_info类型的常引用;可以用type_info的重载的“=”、“!=”操作符比较两类型的异同;type_info的name成员函数返回类型名称,类型为const char *。,49,深 度 探 索,例8-10 typeid示例,#include #include using namespace std;class Base public:virtual Base() ;class Derived: public Base ;,50,深 度 探 索,void fun(Base *b) /得到表示b和*b类型信息的对象const type_info ,运行结果:typeid(b): class Base *typeid(*b): class BaseA base class!typeid(b): class Base *typeid(*b): class Derived,51,虚函数动态绑定的实现原理,动态选择被执行的函数函数的调用,需要通过函数代码的入口地址把函数入口地址作为变量,在不同情况下赋予不同的值,通过该变量调用函数,就可动态选择被执行的函数回顾:第6章介绍的函数指针、指向成员函数的指针虚表每个多态类有一个虚表(virtual table)虚表中有当前类的各个虚函数的入口地址每个对象有一个指向当前类的虚表的指针(虚指针vptr)动态绑定的实现构造函数中为对象的虚指针赋值通过多态类型的指针或引用调用成员函数时,通过虚指针找到虚表,进而找到所调用的虚函数的入口地址通过该入口地址调用虚函数,52,深 度 探 索,53,class Base public:virtual void f();virtual void g();private:int i;,class Derived: public Base public:virtual void f(); /覆盖Base:fvirtual void h(); /新增的虚函数private:int j;,深 度 探 索,54,小结与复习建议,主要内容多态性的概念、运算符重载、虚函数、纯虚函数、抽象类达到的目标理解多态的概念,学会运用多态机制。实验任务实验八,

    注意事项

    本文(C++语言程序设计(清华大学郑莉)八ppt课件.ppt)为本站会员(牧羊曲112)主动上传,三一办公仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知三一办公(点击联系客服),我们立即给予删除!

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




    备案号:宁ICP备20000045号-2

    经营许可证:宁B2-20210002

    宁公网安备 64010402000987号

    三一办公
    收起
    展开