C++多态性
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
10
Hale Waihona Puke Baidu
11.2运算符重载—运算符作友员函数
运算符可以重载为类的友元函数,这样,它就 可以自由地访问该类的任何数据成员。这时,运算 符所需要的操作数都需要通过函数的形参表来传递, 在参数表中形参从左到右的顺序是运算符操作数的 顺序。 对于双目运算符B,如果它的一个操作数为类 A的对象,就应当把B重载为类A的友元函数。该函 数有两个形参,其中一个形参的类型是类A。经过 重载之后,表达式“oprd1 B oprd2”就相当于函数 调用 “operator B(oprd1, oprd2)”。
9
11.2运算符重载—运算符重载的方法规则
有了运算符,编程就显得方便。例如,对于直角三角 形斜边长度公式,用函数的格式表示为: c = sqrt(add(mult(a, a), mult(b, b))); 用运算符的格式表示为: c = sqrt(a*a+b*b); 运算符是函数,除了运算顺序和优先级不能更改外, 参数和返回类型是可以重新说明的,即可以重载。 C++规定,运算符中参数说明都是内部类型时不能重 载。 C++基本数据类型之间的关系是确定的,如果允许定 义其上的新操作,那么基本数据类型的内在关系将出现 混乱。 C++还规定了. 、∷ 、.* 、.> 、?: 这5个运算符 不能重载,也不能创造新运算符。
14
11.2运算符重载—重载流插入运算符和流提取
运算符
C++的流插入运算符“<<”和流提取运算符“>>”是 C++在类库中提供的,所有C++编译系统都在类库中提供 输入流类istream和输出流类ostream。cin和cout分别是 类istream和类ostream的对象。
在类库提供的头文件中已经对“<<”和“>>”进行了重 载,使之作为流插入运算符和流提取运算符,能用来输出 和输入C++标准类型的数据。 在本书前面几章中,凡是用“cout<<”和“cin>>”对 标准类型数据进行输入输出的,都要用 #include <iostream> 把头文件包含到本程序文件中。
21
11.4虚函数—静态关联与动态关联
编译系统要根据已有的信息,对同名函数的调用作出判断。对于 调用同一类族中的虚函数,应当在调用时用一定的方式告诉编译系 统要调用的是哪个类对象中的函数,这样编译系统在对程序进行编 译时,就能确定调用的是哪个类对象中的函数。确定调用的具体对 象的过程称为关联(binding)。在这里是指把一个函数名与一个类 对象捆绑在一起,建立关联。一般地,关联指把一个标识符和一个 存储地址联系起来。 前面所提到的函数重载和通过对象名调用的虚函数,在编译时就 可确定其调用的虚函数属于哪一个类,其过程称为静态关联(static binding),由于是在运行前进行关联的,故又称为早期关联 (earlybinding)。
11.3不同类型数据间的转换 —类型转换函数
用转换构造函数可以将一个指定类型的数据转换为类 的对象,但是不能反过来将一个类的对象转换为一个其 他类型的数据(例如将一个类Complex的对象转换成 double类型数据)。
19
11.3不同类型数据间的转换 —类型转换函数
C++提供了类型转换函数(type conversion function)来解决这个问题。类型转换函数的作用是将一 个类的对象转换成另一类型的数据。如果已声明了一个类 Complex,可以在类Complex中这样定义类型转换函数:
17
11.3不同类型数据间的转换 —转换构造函数
转换构造函数(conversion constructor function) 的作用是将一个其他类型的数据转换成一个类的对象。 先回顾一下以前学习过的几种构造函数: 默认构造函数:
以类Complex为例,函数原型的形式为: Complex( ); //没有参数 用于初始化的构造函数: 函数原型的形式为: Complex(double r,double i); //形参表列中一般 有两个以上参数 用于复制对象的拷贝构造函数:函数原型的形式为: (Complex Complex &c); //形参是本类对象的引 18 用
8
11.2运算符重载—运算符重载的方法
运算符重载的方法是定义一个重载运算符的函数,在 需要执行被重载的运算符时,系统就自动调用该函数, 以实现相应的运算。 也就是说,运算符重载是通过定义函数实现的。运 算符重载实质上是函数的重载。 重载运算符的函数的一般格式如下: 函数类型 operator 运算符名称 (形参表列) { 对运算符的重载处理 } 例如,想将“+”用于类Complex (复数)的加法运算, 函数的原型可以是这样的: Complex operator+ (Complex& c1,Complex& c2);
5
返回目录
11.1多态性概述—多态的实现
多态从实现的角度来讲可以划分为两类——编译时多 态和运行时多态。前者是在编译的过程中确定了同名操作 的具体操作对象,而后者则是在程序运行过程中才动态地 确定操作所针对的具体对象。这种确定操作的具体对象的 过程就是联编(binding),也有的文献称为编联、束定 或绑定。 联编是指计算机程序自身彼此关联的过程,也就是把 一个标识符名和一个存储地址联系在一起的过程,用面向 对象的术语讲,就是把一条消息和一个对象的方法相结合 的过程。按照联编进行阶段的不同,可以分为两种不同的 联编方法——静态联编和动态联编。这两种联编方法分别 对应着多态的两种实现方式。
ostream&
16
11.3不同类型数据间的转换 —标准类型数据
间的转换
在C++中,某些不同类型数据之间可以自动转换。例 如:
编译系统是把7.5作为double型数来处理的。在求解 表达式时,先将6转换成double类型,然后与7.5相加, 得到和为13.5,在向整型变量i赋值时,将13.5转换为整 数13,然后赋给i。 这种转换是由C++编译系统自动完成的,用户不需 干预。这种转换称为隐式类型转换。
– – –
函数重载 运算符重载 虚函数
2
返回目录
11.1多态性概述—多态性的类型
包含多态是研究类族中定义于不同类中的同名成员 函数的多态行为,主要是通过虚函数来实现。 参数多态与类属相关联,类属是一个可以参数化的 模板,其中包含的操作所涉及的类型必须用类型参数实 例化。这样,由类模板实例化的各类都具有相同的操作, 而操作对象的类型却各不相同。
返回总目录
第11章 多态性
教学内容
11.1多态性概述 11.2 运算符重载
11.3不同类型数据间的转换
11.4虚函数 11.5纯虚函数与抽象类
1
返回目录
11.1多态性概述
多态性是面向对象程序设计的重要特征之一。 多态性是指发出同样的消息被不同类型的对象
接收时有可能导致完全不同的行为。利用多态 性技术,可以调用同一个函数名的函数,实现 完全不同的功能。 多态的实现:
6
返回目录
11.2运算符重载—什么是运算符重载
运算符重载是对已有的运算符赋予多重含义, 同一个运算符作用于不同类型的数据导致不同类型 的行为。C++中预定义的运算符的操作对象只能是 基本数据类型。实际上,对于很多用户自定义类型 (比如类),也需要有类似的运算操作,这就提出 了对运算符进行重新定义,赋予已有符号以新的功 能的要求。
7
返回目录
11.2运算符重载—什么是运算符重载
运算符重载的实质就是函数重载。在实现过程中, 首先把指定的运算表达式转化为对运算符函数的调 用,运算对象转化为运算符函数的实参,然后根据 实参的类型来确定需要调用的函数,这个过程是在 编译过程中完成。 所谓重载,就是重新赋予新的含义。函数重载 就是对一个已有的函数赋予新的含义,使之实现新 功能。运算符也可以重载。实际上,我们已经在不 知不觉之中使用了运算符重载。
operator double() {return real;} 类型转换函数的一般形式为: operator 类型名() {实现转换的语句}
20
11.4虚函数—虚函数的作用
在类的继承层次结构中,在不同的层次中可以出现名字相同、参 数个数和类型都相同而功能不同的函数。编译系统按照同名覆盖的 原则决定调用的对象。 人们提出了这样的设想:能否用同一个调用形式,既能调用派生 类又能调用基类的同名函数。在程序中不是通过不同的对象名去调 用不同派生层次中的同名函数,而是通过指针调用它们。例如,用 同一个语句“pt>display();”调用不同派生层次中的display函数,只 需 在调用前给指针变量pt赋以不同的值(使之指向不同的类对象)即可 。C++中的虚函数就是用来解决这个问题的。虚函数的作用是允许 在派生类中重新定义与基类同名的函数,并且可以通过基类指针或 引用来访问基类和派生类中的同名函数。
15
11.2运算符重载—重载流插入运算符和流提取
运算符
用户自己定义类型的数据,是不能直接用“<<”和 “>>”来输出和输入的。如果想用它们输出和输入自己声 明的类型的数据,必须对它们重载。 对“<<”和“>>”重载的函数形式如下:
istream&
operator >> (istream&, 自定义类&); operator << (ostream&, 自定义类&);
12
11.2运算符重载—重载双目运算符
双目运算符(或称二元运算符)是C++中最 常用的运算符。
双目运算符有两个操作数,通常在运算符的 左右两侧,如3+5、a=b、i<10等。在重载双目 运算符时,在函数中应该有两个参数。
13
11.2运算符重载—重载单目运算符
单目运算符只有一个操作数,如!a、b、&c、 *p,还有最常用的++i和i等。 重载单目运算符的方法与重载双目运算符的 方法是类似的。但由于单目运算符只有一个操作 数,因此运算符重载函数只有一个参数,如果运 算符重载函数作为成员函数,则还可省略此参数。
4
返回目录
11.1多态性概述—多态性的实现
编译时的多态性
在C++ 中有两 种多态 性 运行时的 多态性
通过函数的重载和运算 符的重载来实现的。
运行时的多态性是指在程序执行 前,无法根据函数名和参数来确 定该调用哪一个函数,必须在程 序执行过程中,根据执行的具体 情况来动态地确定。它是通过类
继承关系和虚函数来实现的。目的 也是建立一种通用的程序。通用性 是程序追求的主要目标之一。
3
返回目录
11.1多态性概述—多态性的类型
面向对象的多态性可以严格地分为4类:重载多态、 强制多态、包含多态和参数多态。前两种统称为专用多 态,而后两种也称为通用多态。 前面介绍过的普通函数及类的成员函数的重载都属 于重载多态,本章还将讲述运算符重载,上述把加法运 算分别使用于浮点数、整型数之间就是重载的实例。 强制多态是通过语义操作把一个变元的类型加以变 化,以符合一个函数或者操作的要求。前面所讲的加法 运算符在进行浮点数与整型数相加时,首先进行类型强 制转换,把整型数变为浮点数再相加的情况就是强制多 态的实例。
11
11.2运算符重载—运算符作友员函数
对于前置单目运算符U,如“”(取负)等,如果要 实现表达式“UOprd”,其中oprd为类A的对象,则U可以 重载为类A的友元函数,函数的形参为类A的对象oprd。经 过重载之后,表达式“U oprd”相当于函数调用“operator U(oprd)”。 对于后置运算符++和 ,如果要实现表达式 “oprd++”或“oprd”,其中oprd为类A的对象,那么运 算符就可以重载为类A的友元函数,这时函数的形参有两个, 一个是类A的对象oprd,另一个是整型(int)形参。重载 之后,表达式“oprd++”和“oprd”就相当于函数调用 operator++(oprd, 0)和operato (oprd, 0)。
22
11.4虚函数—虚析构函数
析构函数的作用是在对象撤销之前做必要的“清理现场”工作。 当 派生类的对象从内存中撤销时,一般先调用派生类的析构函数,然 后再调用基类的析构函数。但是,如果用new运算符建立了临时对 象,若基类中有析构函数,并且定义了一个指向该基类的指针变 量,在程序用带指针参数的delete运算符撤销对象时,系统会只执行 基类的析构函数,而不执行派生类的析构函数。