《第7章多态性与虚函数概要》由会员分享,可在线阅读,更多相关《第7章多态性与虚函数概要(75页珍藏版)》请在金锄头文库上搜索。
1、第七章 多态性与虚函数,本章内容,多态性概述 运算符重载 虚函数,多态性,多态性是面向对象程序设计的一个重要特征。 多态性:是指发出同样的消息被不同类型的 对象接收时而导致不同的行为。 所谓发消息就是调用类中的成员函数。 多态的实现 函数重载 运算符重载 虚函数,静态联编和动态联编,联编的含义是指把一个消息和一个方法联系在一起,也就是把一个函数名与其实现代码联系在一起。 静态联编是在编译阶段进行的。 动态联编是在程序运行过程中,根据程序运行的需要进行的联编。 当通过对象名调用成员函数时,只可能是调用对象自身的成员,所以,这种情况可采用静态联编实现。 当通过基类指针调用成员函数时,由于基类指针可
2、以指向该基类的不同派生类对象,因此存在需要动态联编的可能性,但具体是否使用动态联编,还要看所调用的是否是虚函数。,静态多态性与动态多态性,静态多态性(静态联编、静态绑定) 联编工作出现在编译阶段。 用对象名或者类名来限定要调用的函数,只能是调用对象自身的成员 动态多态性(动态联编、动态绑定) 联编工作在程序运行时执行 用基类指针或者引用来限定要调用的函数。 在程序运行时根据基类指针指向的对象才能确定将要调用哪个类的成员函数。,静态联编和动态联编,联编的含义是指把一个消息和一个方法联系在一起,也就是把一个函数名与其实现代码联系在一起。 何时将一个变量与其实际类型所定义的行为绑定。 在编译期绑定,
3、属于静态联编或静态绑定; 在运行期绑定,属于动态联编或动态绑定,7,静态联编/绑定(Static Binding),class Myclass public: . . . function( ); function(int); function(int , int); . . . ; void main( ) Myclass a(5); a. function(7); ,用一个成员函数实现两个复数相加运算,规则: 实部和虚部分别相加。 操作数: 两个操作数都是复数类的对象。,复数类名:Complex 成员函数:complex_add() /实部和虚部分别相加 display() /输出复数的实
4、部和虚部,class Complex public: Complex(); Complex(double r, double i); Complex complex_add(Complex ,class Complex public: Complex( )real = 0; imag = 0; Complex(double r, double i)real = r; imag = i; Complex complex_add(Complex ,temp.real =this-real+a.real; temp.imag=this-imag+a.imag;,temp.real =c1.real
5、+ c2.real; temp.imag=c1.imag+c2.imag;,void Complex:display( ) cout “(“real“, “imag“i)“endl; void main( ) Complex c1(3 , 4) , c2(5 , -10) , c3; c3 = c1. complex_add(c2); cout “c1=“; c1.display( ); cout “c2=“; c2.display( ); cout “c1+c2=“; c3.display( ); ,程序输出的结果为: c1=(3,4i) c2=(5,-10i) c3=c1+c2=(8,-6
6、i),问题,如何处理 对象1 + 对象2 ?,14,计算机怎样处理运算符,int num1, num2, num3; num3 = num1 + num2;,C+将各种运算符 都处理成一个 “运算符函数”调用,15,计算机怎样处理运算符,int num1, num2, num3; num3 = num1 + num2;,计算机这样处理运算符: num3 = operator + ( num1, num2 );,int operator + ( int i, int j ) return i+j; ,16,计算机怎样处理运算符,double num1, num2, num3; num3 = nu
7、m1 + num2;,计算机这样处理运算符: num3 = operator + ( num1, num2 );,double operator + (double i, double j ) return i+j; ,17,计算机怎样处理运算符,int num1, num2, num3; num3 = num1 + num2;,计算机这样处理运算符: operator = ( num3 , operator + ( num1, num2 ) );,18,重载 + 运算符,我们打算重载运算符用于对复数类的对象的操作 Complex num1, num2, num3; num3 = num1 +
8、 num2;,The computer thinks of it as: num3 = operator + ( num1, num2 );,Complex operator + ( Complex i, Complex j ) ,运算符重载的实质,运算符重载是对已有的运算符赋予新的含义 必要性 C+中预定义的运算符其运算对象只能是基本数据类型,而不适用于用户自定义类型(如类) 重载运算符主要用于对类的对象以同样的形式按重新定义的方式操作 实现机制 是一种特殊函数的重载。,运算符重载,运算符重载有两种形式: 表达式: 左操作数 + 右操作数 重载为类的成员函数 左操作数 .operator+
9、(右操作数 ) 重载为类的友元函数 operator+ (左操作数 , 右操作数 ),将运算符重载函数说明为类的成员函数 格式如下: class 类名 返回类型 operator运算符(形参表); ; 类型名 类名: operator运算符(形参表)函数体,说明: 重载二元运算符时,参数表中应有一个形参。 重载一元运算符时,参数表应为空(后置+、-除外)。,将“+”运算重载为复数类的成员函数,规则: 实部和虚部分别相加。 操作数: 两个操作数都是复数类的对象。,class Complex public: Complex( )real = 0; imag = 0; Complex(double
10、r, double i)real = r; imag = i; Complex operator+ (Complex ,void Complex:display( ) cout “(“real“, “imag“i)“endl; void main() Complex c1(3 , 4) , c2(5 , -10) , c3; c3 = c1 + c2; /相当于c1.operator+(c2); cout “c1=“; c1.display( ); cout “c2=“; c2.display( ); cout “c1+c2=“; c3.display( ); ,Complex Complex
11、:operator+(Complex ,c1 + c2; 比较下面两种写法,细解运算符重载,Complex Complex : operator+(Complex ,Complex Complex:operator+(Complex ,c1 + c2;,细解运算符重载,Complex Complex:operator+(Complex ,c1 + c2;,细解运算符重载,Complex Complex:operator+(Complex ,c1 + c2;,临时对象,细解运算符重载,生成一个临时对象 调用拷贝构造函数,细解运算符重载: Complex Complex : operator+(C
12、omplex ,c1 + c2;,temp goes away,临时对象,Complex Complex : operator+(Complex ,用隐式的临时对象替换显式的对象temp,在return后面跟的表达式中调用的是类的构造函数, 它创立了一个临时对象,返回值就是该临时对象。 书上是这样写的,比前面的方法效率高。,这里采用Complex对象的引用而不是对象本 身,调用时不再重新分配内存建立一个复制的 对象,函数效率会更高。 而在引用形式参数类型说明前加const关 键字,表示被引用的实参只可读而不可改变。,Complex Complex:operator+(const Complex
13、 ,将运算符重载函数说明为类的友元函数 格式如下: class 类名 friend 返回类型 operator运算符(形参表); ;,重载二元运算符时,参数表中应有两个形参。 重载一元运算符时,参数表应有一个形参。,运算符重载,由于友元函数没有隐含指向当前对象的 this指针,所以, 一个单目运算符重载为类的友元函数时, 其参数个数为1个; 一个双目运算符重载为类的友元函数 时,其参数个数必须为2个。,例:利用友元函数实现两个复数相加运算, 对单目运算符,当以成员函数形式重载运算符时没有参数,以友元函数形式重载运算符时有一个参数; 对双目运算符,当以成员函数形式重载运算符时有一个参数;以友元函
14、数形式重载运算符时有两个参数;,运算符重载小结,两种重载形式的比较,对于单目运算符、复合赋值运算符 “+=、-=、/=、*=” 等常选择用成员函数重载。 对于运算符“=()、-”只能选择用成员函数重载。 对于其他运算符,如“+、-、*、/”等双目运算符,常常选择用友元函数重载,以适应更多的计算形式,对于复数类对象相加来说,用成员函数 实现时, 表达式0.5 + c1将是一个错误的表 达式,因为若将以上加法重载为成员函数 时,表达式0.5+c1将被解释为: 0.5.operator+(c1) 而0.5是一个基本类型的常数,不能自动转 换为复数类对象。,对于复数类对象相加来说, 用友元函数实现时,
15、表达式0.5 + c1可以正确计算,它将被解释成operator+(Complex(0.5) , c1)。,Complex(double r = 0 , double i = 0) real = r; imag = i; ,注:构造函数必须带缺省值,不可重载的运算符,“” 圆点运算符 “*” 成员指针选择运算符 “” 域分辨运算符 “?:” 条件运算符 “sizeof” 长度运算符 除以上五个运算符外,其余运算符均可重载,重载运算符的规则,只能重载C+中已有的可重载的运算符,不能建立新的运算符。 重载运算符时不能改变原运算符操作数的个数、原有运算符的优先级和结合性,也不能改变原运算符对于内部基
16、本类型对象的含义。 如果重载了某个运算符(如“=”),并不意味着重载了相关的运算符(如“+=”、“-=”等)。,对所有对象已重载了“=”和“&”运算符,C+内部已对所有对象重载了“=”和“&”运算符,实现的操作是: “=” :把“=” 右侧对象的数据成员赋给左侧对象的对应的数据成员。 “&” :返回对象的地址。,Complex ,对复数类 Complex 如果没有重载赋值运算符 =, 复数的赋值语义是:,赋值操作,赋值兼容规则,赋值兼容规则:是指在公有继承 的前提下,基类对象与公有派生 类对象之间的自动类型转换和赋 值的规则。,公有继承时 基类对象与派生类对象之间的关系 (1)可以用派生类对象给基类对象赋值,反之不行 。 (2)可以用派生类对象初始化基类对象或基类的引用。 基类对