第四部分编译时多态教学课件

上传人:cl****1 文档编号:567938418 上传时间:2024-07-22 格式:PPT 页数:121 大小:426KB
返回 下载 相关 举报
第四部分编译时多态教学课件_第1页
第1页 / 共121页
第四部分编译时多态教学课件_第2页
第2页 / 共121页
第四部分编译时多态教学课件_第3页
第3页 / 共121页
第四部分编译时多态教学课件_第4页
第4页 / 共121页
第四部分编译时多态教学课件_第5页
第5页 / 共121页
点击查看更多>>
资源描述

《第四部分编译时多态教学课件》由会员分享,可在线阅读,更多相关《第四部分编译时多态教学课件(121页珍藏版)》请在金锄头文库上搜索。

1、第四章第四章 编译时多态性编译时多态性昧架群挪膘评共变膀歪新琅绍氦剧鼓奖吝守镶蹦焰捶琳爵拓拂沫曾包跋屑第四部分编译时多态教学课件第四部分编译时多态教学课件 封装性是面向对象程序设计的基础,可以说没有封装性就没有面向对象的程序设计。封装性从根本上解决了数据的安全性,也为实现不同数据的操作同一性奠定了基础,这种操作的同一性反映了客观世界中规范不同对象行为的一致性需要,它构成了面向对象程序设计多态性的一部分。不过这种多态性必须预先确定操作所施加的数据类型,因此不是完备意义上的多态性,而只是基于对象的多态性。这种不同数据的操作同一性必须在程序编译时静态确定,故称为编译时多态性,或称为静态多态性。实现这

2、种静态多态性的途径是:函数重载和运算符重载。票拽湍踩长适裴慌封宋宗啡示玩庆擞朴辐姑旋芽寞骇确哨峡锌祸子廊删鸦第四部分编译时多态教学课件第四部分编译时多态教学课件本章要点1 函数重载2 运算符重载3 使用成员函数重载运算符4 使用友元函数重载运算符5 自增 + 和自减 - 运算符的重载6 调用运算符 () 和下标运算符 的重载7 动态内存管理运算符的重载8 赋值运算符重载9 输入输出运算符重载10 类型转换(函数)毗锚郝剥媒披华晨械犹宾庐降皋伊倾擅化讳背右呛宝发沂日淫杰怕危德淡第四部分编译时多态教学课件第四部分编译时多态教学课件4.1 函数重载函数重载 函数重载为实现不同数据的操作同一性提供了根

3、本编程机制。函数重载的基本规则: 函数名必须相同:体现了操作同一性。 函数的参数必须不同:体现了同一操作的实现差异 和所施加的数据差异。在面向对象的程序中函数重载表现在两个方面: 类外全局函数重载 类成员函数重载精誉穆殿意枢丹蒂绦雏甭潭购蔗智狙玫席汾图满连粟晰漓态贵骸枯投捞姨第四部分编译时多态教学课件第四部分编译时多态教学课件4.1.1 类外全局函数重载类外全局函数重载 在面向对象程序设计中,全局函数常常用来作为类的友元函数,因此全局函数重载可以用来实现不同类对象的同一类外操作。关于全局函数重载的方法已经在第二章中讲述,本章不再赘述。 为了进一步理解函数重载是如何在编译时确定同一操作施加于不同

4、类型的数据,我们模拟分析 C+ 编译器如何采用 “名子压延” 的方法实现重载函数的调用。 所谓 “名子压延” 是指编译器编译重载函数调用时,先将原重载函数名和参数类型结合起来,以创建新重载函数名。然后用新重载函数名替代原重载函数名。例如,一个程序中有两个重载函数,原型声明为:支名慷杖肺哑竣薪轴硫轩占纷吟饺概瞳愿竖霜壹重锡败掩想维丹党想浚查第四部分编译时多态教学课件第四部分编译时多态教学课件int myAns(float x, int j);int myAns(int I, char c);编译时,编译器首先压延修改这两个重载函数名。修改后的新函数名或许会变成如下形式:int myAnsFLTI

5、NT(float x, int j);int myAnsINTCHAR(int i, char c); 这样,就把原来无法区分开来的相同的函数名变成可以区分的不同的函数名。例如:调用 myAns(float x, int j) 时,则调用 myAnsFLTINT(float x, int j);而调用 myAns(int I, char c) 时,则调用 myAnsINTCHAR(int i, char c)。簧驶凑桑袄把桌糯贫虫汕哨罪刺扼惋覆伎兼藕珠锨篡碴首汞绽凋膝坏敛椰第四部分编译时多态教学课件第四部分编译时多态教学课件假如调用这两个函数的语句为:exam1 = myAns(15.3, 1

6、5);exam2 = myAns(45, a);用新函数名替代原函数名后,使得调用这两个函数的语句会发生如下相应的改变:exam1 = myAnsFLTINT(15.3, 15);exam2 = myAnsINTCHAR(45, a); 注意,上述对函数名的具体压延过程和结果只是为了便于叙述假定的,并非 C+ 编译器对这两个函数名的真实压延结果。缺浑贝宇遂像榷拿蚜胸手吁彼藕辆殃赃续胶退似颅苹怪砒咯抗陇黄拓粟颗第四部分编译时多态教学课件第四部分编译时多态教学课件4.1.2 类成员函数重载类成员函数重载 类成员函数重载分为两类:1 构造函数重载 为类对象的创建和类对象的数据成员赋初值提供不 同的方

7、法。重载构造函数的参数必须不同。2 公有成员函数重载 提供响应相同消息的不同接口方法。这类重载有两 种情况: 同一类中的重载成员函数的参数必须有差别。 派生类中分属于基类和派生类的重载成员函数的 参数可以相同,但基类的重载成员函数被覆盖。 例如:艺厦实洲娄趁拍托四肚词原卖完恃尝又淄乒丰清掺籍驭诫摊藏壳奢蚤贸佐第四部分编译时多态教学课件第四部分编译时多态教学课件class point int x, y;public: point(int a, int b) x = a; y = b; float area() return 0.0; ;class circle:public point int

8、radius;public: circle(int x, int y, int rad):point(x, y) radius = rad; float area()/ 重载成员函数 return float(3.1416)*float(radius)*float(radius); ;江给哈廓坞猫再栖摹喊潭毁株卧倚英除卧李躺抠旧勘畴倡唐封维奄痔跪构第四部分编译时多态教学课件第四部分编译时多态教学课件main() point p(20, 20); circle c(8, 8, 30); cout p.area() endl; cout c.area() endl; cout c.point:ar

9、ea() endl; return 0; 其中 area 是参数相同的重载成员函数。编译过程 中区别这两个不同版本的 area 的情况有两种:筑整雷闭嚷愿撮介跟脱枣擂疯渗女惟皑墩交碟语茫镜招颤垮因露羌芜摘碧第四部分编译时多态教学课件第四部分编译时多态教学课件 使用对象名只能分别调用基类和派生类的参数 相同的重载成员函数。例如: p.area() 将调用 point:area() 方法; c.area() 将调用 circle:area 方法。 在对象名后添加 “基类名:” 可以使用派生类对 象名可以调用基类的参数相同的重载成员函 数。例如: c.point:area() 将调用 point:a

10、rea() 方法。返回盾索痘儡爵仕磷纪足瓤小冯精墨踏敝拳陇炳这徊驳裕亨不捉李隘刘痞谓跃第四部分编译时多态教学课件第四部分编译时多态教学课件4.2 运算符重载运算符重载运算符可以视为是一种特殊的函数,它们可以用一种简洁的,接近自然语言的表达式方式被调用。C+ 拥有一系列的预定义运算符,这些运算符能对所有的预定义类型的数据进行形式一致的操作。也就是说,可以使用预定义类型的数据作参数调用这些运算符函数。例如,加运算符 +:int x, y;float e, f;y = x + y;f = e + f;琼工入柳须权耗稽循诱违府萨证奈半校劣尊怨盘渊古值半鸯柑桃签拎哑揽第四部分编译时多态教学课件第四部分编

11、译时多态教学课件这种对于不同类型的数据使用相同的表达式调用相同的运算符正是通过重载机制实现的。但这些运算符却不能自动施加在自定义类型的对象。例如:自定义的复数类 complex 的定义如下:class complex double real, imag;public: complex(double r = 0, double i = 0) real = r; imag = i; ;巷憾甄佐观奔诞拥宙变实屏槛挣露镰操蝗存桓恤瀑寥克反泰锯手壶寓些谩第四部分编译时多态教学课件第四部分编译时多态教学课件main() complex com1(1.1, 2.2), com2(3.3, 4.4), tot

12、al; total = com1 + com2; / “+”运算符无法对复数进行操作 return 0;产生上述错误的原因很显然,因为运算符 “+” 允许的操作数据类型中不包括 complex 类型,所以编译器就不知道调用该运算符的哪个重载版本来完成相应的操作。肤褂淹炊码澡庶贼南烁牧下斟恫泄铃勒涝夫儒次芍霄曰挨木慷灭呆痊荐莱第四部分编译时多态教学课件第四部分编译时多态教学课件解决的办法就是扩展 “+” 运算符允许操作的数据类型,即为复数类 complex 定义自己的 “+” 运算符操作。C+ 的运算符重载方法为设计不同类对象的同一行为提供了非常有效和方便的手段。运算符重载是通过对运算符函数的重

13、载实现的,运算符函数重载的原型和定义的一般形式如下:函数类型 operator (参数表列);/ 是运算符名的通配符号函数类型 operator (参数表列) 重载操作代码 奖僵坡剔狱丹檀脾畜蛾苇讲沧良何莱彩港祁娃金廊乘吊钾忌蛙链询秉涨咳第四部分编译时多态教学课件第四部分编译时多态教学课件例如,对复数类 complex 的 “+” 运算符重载:class complex double real, imag;public: complex(double r = 0, double i = 0) real = r; imag = i; complex operator + (complex);co

14、mplex complex:operator +(complex &c)complex sum;sum.real = real + c.real;sum.imag = imag + c.imag;return sum;弃趾柞窿敌瘤眺篡劣总伏辽啊锨乡枉漫噎抿悦稻环芬闽鼻排龄棺挠糊钉钙第四部分编译时多态教学课件第四部分编译时多态教学课件4.2.1 重载运算符的规则重载运算符的规则 C+ 不允许定义新的运算符,只能对系统预定义运 算符进行重载。 C+ 的预定义运算符中允许重载的包括:算术运算符+、-、*、/、%关系运算符=、!=、=逻辑运算符|、&、!单目运算符+、-、*、&自增自减运算符+、-位操

15、作运算符|、&、赋值运算符=、+=、-=、*=、/=、%=、&=、|=、=、=内存管理运算符new、delete、new、delete其他运算符()、-、 -*、,、涎铃颤底荣膨舜刮捏灸咐面魏生区斧呆逻茶学机晤访蛹魂禄暑肥便蛛讲邹第四部分编译时多态教学课件第四部分编译时多态教学课件 不允许重载预定义运算符的包括: 重载不能改变预定义运算符函数的参数(操作数) 个数。双目运算符重载后仍为双目运算符,单目运 算符重载后仍为单目运算符。 重载不能改变预定义运算符的原有优先级。 重载不能改变预定义运算符的原有结合律。 重载运算符函数的参数不允许有缺省值。否则编译 器会认为是改变了运算符函数的参数个数。

16、成员访问运算符.成员指针访问运算符.*名域运算符:内存长度运算符sizeof条件运算符?:咳坞巫黎奔垂七婆坷薯瞒粱蹋擅膝桐吱灵醛陪锯鼓迢衣蹲馈陌竿姿冲榨筑第四部分编译时多态教学课件第四部分编译时多态教学课件 重载的运算符必须与用户自定义类型的对象一起使 用,因此重载运算符函数的参数中至少应该有一个 是自定义类对象或类对象的引用。换句话说,重载 运算符函数的参数不能全部是预定义类型对象,防 止用户修改预定义运算符的性质。例如: int operator +(int a, int b) return a b; 显然,这是绝对不允许的。 对于双目运算符,允许两个参数都是自定义类对 象,例如两个复数的

17、加运算;也允许一个参数是自 定义类对象,另一个参数是预定义类型对象,例如 一个复数与一个实数的加运算。帆比贵逢讹料宁城恶瑰公芒狱巩宛井业抠烂耍措宁俭教康串烙桅娶藕桑本第四部分编译时多态教学课件第四部分编译时多态教学课件 complex operator +(double d, complex& c) return complex(d + c.real, c.imag); 系统会为每个自定义类缺省重载了赋值运算符 “=”和取地址运算符 “&”,其他运算符都需要根据需要进行重载定义。其中: 赋值运算符 “=” 用于同类对象之间的数据成员赋值操作。一般情况下,缺省重载的赋值运算符 “=” 可以满足要

18、求,但遇到类的数据成员中包含了动态数据指针,则使用缺省重载赋值运算符就可能发生危险,因此必须重载新的赋值运算符。 取地址运算符 “&” 用于计算返回对象在内存中的起始地址。脾幌龟匣销灵甩旗痘付射祈饮檄绊慰透锈赡疵檄钢趟哮曰妻彦攫挛苫拜糊第四部分编译时多态教学课件第四部分编译时多态教学课件 虽然可以任意定义重载运算符的操作功能,但应该 使重载运算符的功能类似于被重载运算符作用于预 定义类型数据时的操作功能。 运算符重载函数可以是运算所施加类对象的成员函 数,也可以是该类的友元函数,如果不需要访问类 的私有数据成员,还可以是既非类成员函数也非友 元函数的普通函数。禄苫俏阻冻墒认獭申窝投涂吕着讶卡尾

19、牛功阴咕值跃连家绅貉欠凭泄淖昼第四部分编译时多态教学课件第四部分编译时多态教学课件 在 Java 中虽然也不乏运算符重载的例子,例如:String str = hello + there;该表达式相当于在 C+ 中的表达式:string str = hello + there;上述表达式都是因为对 Java 的 String 类型和 C+ 的 string 类型的进行了 “+” 运算符重载的结果。但要注意的是在 Java 中不允许用户进行运算符重载。返回酝左选膏伙为玉鸽它络舷信罐添腋芬咯碰繁吱婴绰辙裹勘胃劳们授吮记啸第四部分编译时多态教学课件第四部分编译时多态教学课件4.3 使用成员函数重载运

20、算符使用成员函数重载运算符1 使用成员函数重载运算符的语法形式 在类定义体中声明要重载的运算符成员函数 type 运算符函数类型; operator 运算符函数名关键字; 要重载的运算符名; 参数表 被重载运算符所需的右操作数。 参数个数 = 运算符所需操作数个数 - 1,缺省 的左操作数必须是运算符所属类对象。例如:type operator (参数表);背螟添题溢怒甥厢夹撒颧砍配枝摘唆合亥韭撵媒团袖迟控穴释墅谢俊逸伍第四部分编译时多态教学课件第四部分编译时多态教学课件 class complex double real, imag; public:complex operator + (c

21、omplex&); ; 定义运算符成员函数 例如: complex complex:operator + (complex& com) return complex(real + com.real, imag + com.imag); type 类名:operator (参数列表) 显巳轴巫择蝗盒蜡玉唇险蟹燃馒官哭蕉缆桑钝违涨拱驻赞据绵址褪朽革骄第四部分编译时多态教学课件第四部分编译时多态教学课件 重载运算符的使用 运算符的左操作数必须是该运算符成员函数所属 类的对象。 双目运算符 例如: complex com1, com2, com3; com3 = com1 + com2; 或 com3

22、 = com1.operator +(com2);表达式形式:对象名 参数对象名;函数形式: 对象名.operator (参数对象名);萝玻偿尿涛沛膳八忌白圭多罕瘸肝厉腾肇雏竹敌政刀嚷缆娟需充缕析量实第四部分编译时多态教学课件第四部分编译时多态教学课件 单目运算符 例如: complex com; +com; com+; 或 com.operator +(); com.operator +(0);表达式形式:对象名;对象名;函数形式:对象名.operator ();对象名.operator (0);糙雹寥玖掳伶媳牛乒务窜代诺滇伐理彦昭纲浴祝嫁剂曰益讲澎成抹枚秽等第四部分编译时多态教学课件第四部

23、分编译时多态教学课件2 用成员函数重载运算符的使用实例例例4-14-1 定义了一个表达三维空间位置的简单类 three_d,在此类中含有三维空间位置的坐标。通过运算符重载来实现对此类对象的 +、 和 = 运算。注意:定义中 + 和 运算符函数的返回值不应是被加对象和被减对象,而 = 运算符函数的返回值必须是被赋值的对象。这都是运算符的操作含义所决定的。返回糊毒萤犀锹苹飞纤最婴扰呵鸥基炙沼斥图透市祁有父喇蓄甥钾濒顽屋叙淡第四部分编译时多态教学课件第四部分编译时多态教学课件4.4 使用友元函数重载运算符使用友元函数重载运算符1 使用友元函数重载运算符的语法形式 在类定义体中声明重载运算符友元函数

24、friend 友元函数关键字 type 运算符函数类型; operator 运算符函数名关键字; 要重载的运算符名; 参数表 被重载运算符所需的操作数。 参数个数 = 运算符所需操作数个数。 例如: friend type operator (参数表);蛙缨耿邀借药剿刹火阉谭氦尚艾瘁途芋葬埋憋阅殃铡肠良丈厌绦抉伶般疫第四部分编译时多态教学课件第四部分编译时多态教学课件 class point int x, y; public:friend point operator +(point&, point&); ; 定义重载运算符友元函数 例如: point operator +(point& p1

25、, point& p2) return point(p1.x + p2.x, p1.y + p2.y); type operator (参数表) 痹杆霹褪玄趴牢驰历隧渭虏肚假辆汛虐推陷南莆绅蹬臭戊鸡挨早玻画僧跋第四部分编译时多态教学课件第四部分编译时多态教学课件 重载运算符的使用 双目运算符 例如: point pt1, pt2, pt3; pt3 = pt1 + pt2; 或 pt3 = operator +(pt1, pt2);表达式调用:参数对象名1 参数对象名2;函数调用:operator (参数对象名1,参数对象名2);溃沸讼玩放蚂溺方爷串悬感署泣茫体淑吵蝉量臭硒炊魁铺限獭际嗅疡甄喊

26、第四部分编译时多态教学课件第四部分编译时多态教学课件 单目运算符 例如: point pt; +pt; pt+ 或 operator +(pt); operator +(pt, 0);表达式调用:参数对象名; 参数对象名;函数调用:operator (参数对象名); operator (参数对象名, 0);读蟹外验敛汉售遍忌眼族废湖介狡胰铆遂邱锭衷绅陷乘孜胁寄钠毒租睛溃第四部分编译时多态教学课件第四部分编译时多态教学课件2 使用友元函数重载运算符的应用实例例例4-24-2 使用友元函数重载运算符的方法实现复数的四则运算,复数运算规则如下:(a + bi) + (c + di) = (a + c

27、) + (b + d)i;(a + bi) - (c + di) = (a - c) + (b - d)i;(a + bi) * (c + di) = (ac - bd) + (bc + ad)i;(a + bi) / (c + di) = (ac + bd) + (bc - ad)i)/(c2 + d2);定义一个复数类 complex,并声明和定义相应的友元函数,用于重载运算符 +、-、*、/。煞碗骄刃澳溢刻轮厘玲鸣歹痊褐秒蜗甫提帐骚乒梗儒辈冬巫汁柒殿反菠暗第四部分编译时多态教学课件第四部分编译时多态教学课件例例4-34-3 使用友元函数重载运算符的方法实现集合运算。集合可以用数组或链表表

28、示,在该数组或链表中不允许包含重复元素。定义整型数集合 set,元素个数用整型变量 card 表示。集合的操作包括向集合中追加元素、显示集合的全部元素以及使用友元函数重载运算符的方法实现的集合的主要运算,这些运算包含: 判定某一个元素属于集合的运算符 &; 判定两个集合相等的运算符 =;雪鸭春俐绪避拯依茵笔插峨唇钳留正昏匡符齐引奈吓刮倍个固韩栅讽撕器第四部分编译时多态教学课件第四部分编译时多态教学课件 判定两个集合的不等于运算符 !=; 两个集合的交运算符 *; 两个集合的并运算符 +; 判定某集合是另一集合的子集运算符 =; 判定某集合是另一集合的纯子集运算符 。拣弦辗匪婚噬道腾泽巷漆椽苫珊

29、尤琐蒂砒艺逆矫砸艇侯敲形贺萝歪愚撒乞第四部分编译时多态教学课件第四部分编译时多态教学课件4.4.1 两种运算符重载方法的比较两种运算符重载方法的比较1 参数数目: 双目运算符 重载运算符的成员函数只有一个参数,用于 表示表达式的右操作数。 重载运算符的友元函数有两个参数,分别用 于表达式的左、右操作数 单目运算符 重载运算符的成员函数无参数。 重载运算符的友元函数带有一个参数,用于 表示表达式的唯一操作数。崇家嘘温茎拇呜菊邦诵谴捎钓繁蜀等膝曼午绊忍刀掣耶祭申恭候磋旷亲诵第四部分编译时多态教学课件第四部分编译时多态教学课件2 无论是使用成员函数还是友元函数重载的运算符, 调用它们的表达式形式是一

30、致的,而调用它们的函 数形式是有差别的。表达式形式友元函数调用形式成员函数调用形式 a b operator (a, b) a. operator (b) a operator (a) a. operator () a operator (a, 0) a. operator (0)让趴烷牲趁创拴霍肠烂背末茫篇荷耙梗凉枫僚藐泌奥驻沤逮赊非咽彦赣梯第四部分编译时多态教学课件第四部分编译时多态教学课件3 大部分运算符重载函数既可以是成员函数,又可以 是友元函数。究竟选择哪一种好呢?要视实际情况 和程序员的习惯。但是应注意以下情况: 对于双目运算符,如果使用成员函数重载,则在 有些情况下会产生操作数类

31、型错误。例如: class complex double real, imag; public:complex operator +(double x); ; complex complex:operator +(double x) return complex(real + x, imag); 冤厘灯瞎序迎城迈播依嘎峰呜摇精梗羡件熏蚌排帜懂香纪延塘辉葬衷烹逾第四部分编译时多态教学课件第四部分编译时多态教学课件 对 complex 的对象 com 进行如下的 + 运算: com = com + 100.0; 由于对象 com 是 + 运算符的左操作数,所以它调 用了 complex 类重载的

32、+ 运算符,把实数 100.0 加 到 com 的实部数据成员 real 上。如果按照 + 运算 符操作数的交换律,将上面的表达式写成: com = 100.0 + com; 则会引起操作数类型错误,无法完成表达式所要 求的操作。这是因为 complex 类 + 运算符的左操 作数是 complex 类对象,而表达式的左操作数是 实数,无法调用 complex 类 + 运算符函数。沈剿程谗柄项快栖携缩横忌疥朝短跨没徒峡绅励瞄铺东纯湍逮龙砌唇况沃第四部分编译时多态教学课件第四部分编译时多态教学课件 如果使用两个友元函数来替换上述 complex 类的 + 运算符重载: friend operat

33、or +(complex com, double x); friend operator +(double x, complex com); complex operator +(complex com, double x) return complex(com.real + x, imag); complex operator +(double x, complex com) return complex(x + com.real, imag); 则可避免上述问题,因为友元运算符函数的两个 操作数都是显式地传递给运算符函数的,能满足 加运算操作数的交换律。皮将补淹硼美吩域赛别威尚译汪缚卵而费

34、单瘪霉夜末巍备饲阴炎款夯您捍第四部分编译时多态教学课件第四部分编译时多态教学课件 所以一般建议使用友元函数重载双目运算符,特 别是期望双目运算符的左操作数的类型能够隐式 转换的情况,则重载双目运算符必须使用友元函 数,而不能使用成员函数。 若一个运算符需要修改其操作所施加对象(特别 是该对象为该运算符的第一操作数)的状态,则 选择使用成员函数重载运算符不破坏类对象的封 装性,更符合面向对象程序设计的原则。返回葵豆久椭毡咎蹬族辨寅搔珊弛淳翔揭宗釉韵枢墨骡排痢盐龟淳凭剪锋骨媳第四部分编译时多态教学课件第四部分编译时多态教学课件4.5 自增自增 + 和自减和自减 - 运算符的重载运算符的重载 从运算

35、操作的正确性考虑,使用成员函数还是使用友元函数重载自增运算符 + 和自减运算符 - 的效果是一致的。但从面向对象设计原则出发,类对象的自增和自减运算实际上是对被封装的类数据成员依次进行的。因此,建议使用成员函数实现自增运算符 + 和自减运算符 - 的重载。 使用 + 和 - 的表达式形式分为前缀和后缀两种形式,这两种形式对操作数的最终修改虽然相同,但运算符函数的返回值不同,前缀形式返回修改后的操作数,而后缀形式返回修改前的操作数。例如:佯孪氖延潮烈曲外冬媒恼类舱梗槛联浇裔扎门摄跳鹰湍段片胀驶狸历疙汞第四部分编译时多态教学课件第四部分编译时多态教学课件 int i = 0, j = 0; i+;

36、 +j; cout i , j endl;/ 显示1,1 cout i+ , +j x = x;this-y = y; 调用 类对象名(调用参数列表);例如: point pt; pt(50, 80);萝虱膳慕剑斋昭程舀娥规涯豢撰夯聋氨丫盂扇壳铃仅消华无聚插霞芽琅堡第四部分编译时多态教学课件第四部分编译时多态教学课件例例4-54-5 是一个使用成员函数重载调用运算符 “()” 的简单实例,有助于对调用运算符定义形式、使用方法和用途的理解。注意,调用运算符函数的右操作数,调用参数列表中的参数也允许有缺省参数值。巍奉挡口留兄邪限畴整跃盏兑恩逐疽院帆逃娱俘雌锨那所制积问颤寿彼守第四部分编译时多态教学

37、课件第四部分编译时多态教学课件2 下标运算符 “” 与调用运算符相似,下标运算符可以用下标访问表 达式的形式对运算符操作所施加对象的相关数据成 员进任何需要的访问和操作,例如,读写矩阵类对 象封装的内部矩阵(数组)的某个指定元素。调用 该运算符的表达式的一般形式为: 类对象名 下标列表; 可以认为下标运算符也是一个双目运算符。 左操作数: 必须是该运算符操作所施加的类对象。 右操作数: 为访问类对象所需要传递的一组下标, 这组下标可以由任意个数的整型对象组 成,不允许无下标。三抽赎聘骆骂极泵拧斜年桥船刨辖阿九德孝谎叛港范肋雇掀岂念夸试裹庐第四部分编译时多态教学课件第四部分编译时多态教学课件显然

38、,应该使用成员函数重载下标运算符。 原型 返回类型 operator (); 其中返回类型可以是除 void 外的任何合法类型。 例如: class Matrix double mt10, 10; public:double& operator (int, int); ;褪瞒邹蒲探省躯隔舔窘内裂医知剧赫饱渔蜗嗽院斯秆谷拈涯劝涩佐贬趟尔第四部分编译时多态教学课件第四部分编译时多态教学课件 定义 返回类型 类名:operator (下标列表) 例如: double& Matrix:operator (int x, int y) if(x -1 & x -1 & x 10) return mtx,

39、y; 调用 类对象名 调用参数列表;例如: Matrix matrix; matrix5, 8 = 38.5;暴忠餐吹缝糠詹济苍秦怎镇篱惋漫烟翠公配兢邵缝吓缝舌杀抑箔旦醇碳纬第四部分编译时多态教学课件第四部分编译时多态教学课件例例4-64-6 是一个使用成员函数重载下标运算符的简单实例,有助于对下标运算符定义形式、使用方法和用途的理解。 通过重载的下标运算符函数可以方便地访问私有数 据成员 divisionTotals 中的每一个元素。 重载下标运算符 “” 时,返回一个 int 的引用,使得 通过重载的 “” 访问的元素既能够读,也能够写。 因此,下标表达式可以出现在赋值语句的左边。偶试总沼

40、员硒赣凌版埂欲锅逆辨踊湾佳蚁望立吧矛革褂碰羌罐讨插狈沙受第四部分编译时多态教学课件第四部分编译时多态教学课件例例4-74-7 是一个用来处理矩阵运算操作的实例。 假定有一个实数矩阵,需要对它进行加法、减法和乘法运算(通过重载运算符 +、-、*来实现),为此需要通过重载函数调用运算符 (),来返回矩阵元素,以便在实现矩阵的加、减、乘运算中使用。注意:矩阵的析构函数 matrix:matrix() if(elems) / 判断矩阵是否不为空delete elems;elems = 0; 返回抓景扦掉还千膏板倡党耍晚暮辕乡醋镭逆宝誉尘绳也痈彼椭得国加士谍从第四部分编译时多态教学课件第四部分编译时多态

41、教学课件4.7 动态内存管理运算符的重载动态内存管理运算符的重载用于动态内存管理的运算符包括 new、delete (用于单个对象的内存分配和释放)和 new、delete (用于对象数组的内存分配和释放)。系统预定义的这两对运算符可以适用于所有类型对象的动态内存管理,但不能确保对所有类型对象的动态内存管理都高效,尤其是对那些占用内存空间小、结构简单的类型对象,使用那些为了适应复杂情况管理的时、空开销是没有必要的,因此大大降低运行效率。解决这一问题的办法就是重载动态内存管理运算符,定义适应类型对象动态创建和撤消的内存管理操作。左档殖欣分占坍常蛆搁据扔湿炙圈悸隐疡狐疑壹缀设痢皑剃楚芽假岂姑汰第四

42、部分编译时多态教学课件第四部分编译时多态教学课件重载动态内存管理运算符的方式有两种: 全局方式:重载的动态内存管理运算符完全替代了 原有的动态内存管理运算符 new、delete、new、 delete 。这种方式一般很少使用,除非确实需要修 改原来的通用管理算法或添加所有类型对象创建和 撤消都需要的附加操作。 局部方式:重载的运算符函数只对某个特定类对象 的创建和撤消有效,这是重载动态内存管理运算符 的常用方式。显然,将动态内存管理运算符重载函 数定义为成员函数更符合面向对象程序设计原则。贺龄级馅抽渊示怎墅劣揭候缎泡俐废岂饱间碎吉丝崇省剔泛圆襄贾祈谁藩第四部分编译时多态教学课件第四部分编译时

43、多态教学课件重载 new 和 delete 运算符的一般方法: 定义可以存放 n 个被管理类型对象的静态数组,作 为动态分配的内存储备。 定义空闲链,将被回收的对象内存链结起来。 定义指示变量,用于指示作为内存储备的静态数组 空间是否已经被初次顺序分配完。 重载动态内存分配运算符 new,用于顺序从静态数 组中或从空闲链中为动态创建的对象分配空间。 重载动态内存回收运算符 delete,用于释放动态创 建的对象,并将该被释放对象的内存空间链结到空 闲链中。魄撵获弃亨垢漾锨延臻削悄尘顽扼嘲宰芜跪甜撤胺钟用袭桩非驾旬忘殿吓第四部分编译时多态教学课件第四部分编译时多态教学课件例例4-84-8 定义适

44、用于 point 类对象动态创建和撤消的内存管理运算符 new 和 delete 重载成员函数,并测试使用重载的 new 和 delete 动态创建和撤消 point 类对象的情况。注意,此例中重载的 new 和 delete 运算符每次只能为单个 point 类对象分配和释放内存 ,而如果分配和释放point 类对象数组则需要重载 new 和 delete 运算符。千焦帆尔歇苏岳烙谅症喻淄猾血电坦论婶港夺症僵替托滩砰议绵愁专户效第四部分编译时多态教学课件第四部分编译时多态教学课件1 问题分析 分配一个具有足够空间静态数组(数组元素的结构 应满足存放 point 类对象属性和动态分配和释放的需

45、 要。对该数组的分配和释放操作示意如下:used00freelist从数组中顺序分配x1 y11x2 y22x3 y33x4 y44used00freelist随机删除已分配元素x1 y11 2x3 y33 4x2 y2x4 y4x2 y2x4 y4绥佃漱国天兵富可伦溃攻班赁灸藏苛韶姑弛秸葛征峙赣黄柯椒蛰吞浸闰蝇第四部分编译时多态教学课件第四部分编译时多态教学课件 其中: 静态数组的元素由存放位置属性 x 和 y 的单元, 以及用于存放被释放元素地址的指针单元组成。 静态数据成员 used 用于指示从静态数组中已经被 初次顺序分配的元素个数。 静态数据成员 freelist 用于指向被释放回收

46、的元素 链表。 元素的动态分配和释放操作分为两种情况: 静态数组中的元素未被初次顺序分配完,即 used 的值小于静态数组的元素总数时(元素第一次被分配):棱慧保今柜衅穿胎溜尺福捌寿绍焕章猪酶迟暮惨赐烈呸突齐隙耘缩丈库砌第四部分编译时多态教学课件第四部分编译时多态教学课件 分配:以 used 的值为下标,为用户动态分配 一个元素,并修改 used 的值。 释放:将新释放的元素与 freelist 指向的存放 已释放元素的空闲链连接,并使 freelist 指向 修改后的空闲链。 数组中的元素已被初次顺序分配完,即 used 的 值大于静态数组的元素总数时(数组中元素的再 分配): 分配:如果被

47、释放元素的空闲链不为空,则从 空闲链中动态分配一个元素,并修改空闲链。可醇擞巾泛斌囚嫌靠葵根苦蝶夏扫栗饭思墒胁彦秦唾炒彩铁蓑宜鄙跺望丢第四部分编译时多态教学课件第四部分编译时多态教学课件 释放:将新释放的元素与 freelist 指向的存放 已释放元素的空闲链连接,并使 freelist 指向 修改后的空闲链。 将运算符 new 和 delete 重载函数声明和定义为 point 类的成员函数,point 类的类图被描述如下:point-x:int-y:int-used:intstatic-freelist:blockstatic+operator new(in size:int)+opera

48、tor delete()+print()运良翘诛巾轻杂之除印席棋垣撇狮勇殖讫撤埠藉蔓啥炉侦厩兄甸愉课蚤犯第四部分编译时多态教学课件第四部分编译时多态教学课件2 详细设计 类设计 point 类 类定义class point int x, y;static int used;static block *freelist;public:point(int vx, int vy);void* operator new (size_t size);void operator delete ();void print();辗湾贮诧咱衰粟脆汕桂吞婆搽疵阎菊拼芭面符脱帽萤埠茹严目耐肆时毅桌第四部分编译时多态

49、教学课件第四部分编译时多态教学课件 其中,block 为用于动态定义 point 对象时,分 配其属性空间的数据结构:struct block int x, y;block *next; 算法描述 重载运算符 new 的算法 N-S 图: used 数组 block 的元素个数Yes No freelist 0Yes Nores = freelist修改 freelistres = 0res = &blockusedused = used + 1返回结果指针 res含梦倾孵讣吹茁命田铜万倍嗽坍场长漠砧秦琐批欢妇媒厌陇竹饶澈膝驻械第四部分编译时多态教学课件第四部分编译时多态教学课件 重载运算符

50、delete 的算法 N-S 图: 类的应用 在主函数 main 中动态创建 point 对象、显示对象 信息;然后动态释放动态创建 point 对象,用以测试重载的动态内存管理运算符 new 和 delete 的功能。返回被释放元素的指针 next = freelistfreelist = &(被释放元素的指针)阀孙骆楷碉汝庆澳鼻慌钮赤脑丝陷晕郸碑绒勋祭蝇癸匣喝自蜕十注荐拨叫第四部分编译时多态教学课件第四部分编译时多态教学课件4.8 赋值运算符重载赋值运算符重载类对象之间的赋值操作是在一一对应的数据成员之间进行的。所以赋值运算符的重载函数应作为类的成员函数。赋值运算符成员函数的原型、定义和调

51、用表达式如下: 原型 类名 operator =(const 类名&);例如: class point int x, y; public:point operator = (const point&); ;耶丝废赠某刺眷沼邑疾舅咐扛勾哗馏莆特蚤罢砰廖吻掣泌耶升腿章争光嗜第四部分编译时多态教学课件第四部分编译时多态教学课件 定义 类名 类名:operator = (const 类名& 对象名) 例如: point point:operator = (const point& pt) x = pt.x;y = pt.y;return *this; 味泽趁泉氰少板驱叠锑辜棺徒收学拣储脱玫冬卒企江砍销

52、细坐诽拙店苔盒第四部分编译时多态教学课件第四部分编译时多态教学课件 调用 对象名1 = 对象名2;例如: point pt1, pt2; pt2 = pt1;系统会为每一个类缺省定义一个隐含的赋值运算符成员函数。通常情况下,缺省赋值运算符是可以胜任类对象之间的赋值操作,但在某些特殊情况下,如类中有指针类型的数据成员时,使用缺省赋值运算符就可能产生错误。例如:蚂谩唉螟奄送堂冠蕴萧沪耶压虐撑励魔酪善蜂买滥笺哇逞臃幻钙樟风趴阉第四部分编译时多态教学课件第四部分编译时多态教学课件#include #include class stringchar* ptr;public:string(char* s)

53、ptr = new charstrlen(s) + 1;strcpy(ptr, s);string() delete ptr; void print() cout ptr endl; ;沥肉束唉即八陋锑南符怂倪薪立圆快悟吮敢于右祝使贷奥彤扳正霹勇宁惮第四部分编译时多态教学课件第四部分编译时多态教学课件void main()string p1(Chen);string p2(“Zhang);p2 = p1;cout p2:;p2.print();cout 输入运算符 “” 是输入流类(将在第八章中详细讲述)的成员函数。该运算符也是一个双目运算符,它的左操作数必须是输入流类对象的引用,表示被输入的

54、信息必须来自标准的输入流设备;而右操作数是接收输入信息的指定类对象的引用。因此,为自定义类重载的输入运算符函数只能是类的友元函数。踊苦蓟壳羔杯肥伐涵携钢雨隘迈婚呼朝睫括刀祟恐疙演社绳噎染蕾石形此第四部分编译时多态教学课件第四部分编译时多态教学课件1 原型 friend 输入流类& operator (输入流类&, 类名&); 例如: class point int x, y; public:friend istream& operator (istream&, point&); ;怜菠从沙自门毒谴碱河倒柄牛喉笼莱贴单戊弄此盎识旦笆瑶棺奖氮茅豁巍第四部分编译时多态教学课件第四部分编译时多态教学课

55、件2 定义 输入流& operator (输入流& 流对象名, 类名& 对象名) return 流对象名; 例如: istream& operator (istream& in, point& pt); cout pt.x pt.y;return in; 痘硕芬卵化类烘痪影玄等脂塞赞妓芯恕得碰晕捉抬遁张胁腑伴义颊鹊褥革第四部分编译时多态教学课件第四部分编译时多态教学课件3 调用 cin 类对象名; 例如: point pt; cin pt;姜追萨吸壕帮条蛀币熏灌祸蹬炳会硬大苔枢误蓝意危吧容法蜘沁些车娱手第四部分编译时多态教学课件第四部分编译时多态教学课件注意: 输入运算符重载函数的第一个参数的

56、类型必须是输 入流类 istream 对象的引用,形参名(流对象名)可 以使用任何合法的标识符。 输入运算符重载函数的第二个参数的类型必须是接 收输入信息的指定类对象的引用,例如 point&, 而 不能使用指定类名,例如 point。 输入运算符重载函数的返回类型必须是输入流类 istream 对象的引用,并且在函数体中由 return 返回 的输入流类对象的引用名必须与第一个参数的形参 名(流对象名)一致。风洲浙中骇寥上熏啮沧陌虱眩墙甘樊丙氛酮四琶壮侦嗡摩观焊眨筹绪颠活第四部分编译时多态教学课件第四部分编译时多态教学课件4.9.2 重载输出运算符重载输出运算符 “ 输出运算符 “” 是输出

57、流类(将在第八章中详细讲述)的成员函数。该运算符也是一个双目运算符,它的左操作数必须是输出流类对象的引用,表示信息必须被输出到标准的输出流设备;而右操作数是输出信息的指定类对象。因此,为自定义类重载的输入运算符函数也只能是类的友元函数。令宛鄂悸吸挞匈惮扣哭秒耿沪赫窃宗平胡槐恒斤烬恐掖贮押浚齿卿奴社未第四部分编译时多态教学课件第四部分编译时多态教学课件1 原型 friend 输出流类& operator (istream&, point&);friend ostream& operator (ostream&, point); ;爪滦讲殉踞嫁赂慑伐融蹄河岗咀僧沧铂捉戳诣递遭倘防愁载蛋没哮讳压频第

58、四部分编译时多态教学课件第四部分编译时多态教学课件2 定义 输出流& operator (输出流& 流对象名, 类名 对象名) return 流对象名; 例如: ostream& operator (ostream& out, point pt); out “点的位置坐标 x 和 y:”;out pt.x “,” pt.y endl;return out; 孺橇航瑞佛娄凶鸯粒渺雇留摄疟帛阵测阐酗碴乏澜淌玫澄混伍篆笺淘纤希第四部分编译时多态教学课件第四部分编译时多态教学课件3 调用 cout pt; cout 和输出运算符 和输出运算符 进行了重载,使它们能对按照指定形式(例如由分子分母组成的分

59、数形式,3/8)表示的有理数进行标准输入输出操作。返回厕噎绥禁办谰烬款嚷肆黑闺呀辅中振披桨饮咱后柴怖娠哉啃智乃璃慌鸥淄第四部分编译时多态教学课件第四部分编译时多态教学课件4.10 类型转换(函数)类型转换(函数) 所谓类型转换是指编译器将一种数据类型值转换为另一种数据类型值的功能。1 在 C+ 中,系统预定义类型和用户自定义类型的对 象均可以进行类型转换。2 类型转换有两种形式: 隐式类型转换 如果发生了对象类型与表达式的语法要求不符的情况,编译器能按照语言标准确定的规则自动地将对象的类型进行转换。 显式类型转换 用户使用特定的语法表示形式(类型转换法形式或函数法形式)指示编译器将对象的当前类

60、型转换为指定类型。乘禁淫券秘鸳吸掺戳追盖更铬邑拜粱匡详峦撰氰棕舒袁邹腥池冕好嘻并叼第四部分编译时多态教学课件第四部分编译时多态教学课件4.12.1 预定义数据类型间的类型转换预定义数据类型间的类型转换1 隐式类型转换 如果赋值表达式 A = B 中操作数的类型不一致,则赋值运算符右端 B 会自动转换为 A 的类型后再进行赋值运算。 当 char 或 short 类型变量与 int 类型变量进行运算时,char 或 short 类型变量会先自动转换成 int 类型,然后再进行运算。 如果参与算术运算的两个操作对象类型不一致,则两个操作对象中精度低的类型会自动转换为精 度高的类型。焉钻祟咨氨宴笋怨

61、炒赶篮坷赋学掷阻魄虽邹弯霉桐蓖蜜圆倍闻敝陛任左尼第四部分编译时多态教学课件第四部分编译时多态教学课件2 显式类型转换 强制转换法 格式:(类型名)表达式 例如:int i, j;cout (float)(i + j); / 将 i + j 的运算结果强制转换成 float 类型后输出 函数法 格式:类型名(表达式) 例如:int i, j;cout float(i + j);/ 将 i+j 的运算结果作为类型函数 float 的参数。 两种方法实现的效果是等效的。使用显式类型转换 在有些情况下是必要的,例如:罚饭洞呵滦隘沤绘檀佃艰脖楷柿补陶韦寓欢落咱胃框辨襟坞湘咳帧鹰砒酱第四部分编译时多态教学

62、课件第四部分编译时多态教学课件 int a = 5, b = 8; printf(a = %f b = %f, a, b); 会产生不可期望的结果,例如: a = 8192.000001 b = 0.000000 使用显式转换将上面的输出语句改写为: printf(a = %f b = %f, float(a), float(b); 就可以得到可以预期的结果: a = 5.000000 b = 8.000000鲜啃炕挛蜕裔组涎厨俺螟希氏不角俘徽蛮靡睛阑绷逾蜡该仲援恬拭氧贡道第四部分编译时多态教学课件第四部分编译时多态教学课件 结构类型与预定义类型之间在数据的组成结构上没 有任何共同之处,因此不

63、能进行这两种类型变量的 显式类型转换,但可以进行这两种类型指针变量的 显式类型转换。例如: #include struct example int y;float z; ;跪郎金敝曲纬由蝶掺颤仑箔掩韩怂逊典储积心脚秉疽址隔牙幢肄泻孺气蝇第四部分编译时多态教学课件第四部分编译时多态教学课件main() char *str = Windows!; int *p = new int; *p = 67; example *ex1, *ex2; ex1 = (example*)str; / str 强制转换为 example 指针类型 ex2 = (example*)p;/ p 强制转换为 exampl

64、e 指针类型 cout y z n; cout y z n;从舶辑施赤骚譬谓嗓与晌贷阉涪咖星啮扬蚂冤告菏澎充募从暴密扩俭辙挞第四部分编译时多态教学课件第四部分编译时多态教学课件 delete p; str = (char*)ex1;/ ex1 强制转换为 char 指针类型 cout str n; return 1; 输出结果可能如下:26999 4。855453e+3367 0Windows!摩阁奔堕昭岸蛮溯雀数埃辗篡纳菊祝吐死熔温隶惋惦薪捧魔曝巴贷稳湘滥第四部分编译时多态教学课件第四部分编译时多态教学课件4.12.2 通过构造函数进行类型转换通过构造函数进行类型转换 在面向对象程序设计中自

65、定义类型之间以及自定义与预定义数据类型之间的转换是经常发生的。通过类的构造函数进行类型转换就是方法之一,进行这种转换的前提是:如果 A 类对象能够转换为 B 类对象,则类型 B 必须有一个仅以 A 类对象为参数的构造函数。换句话说, 就是 B 类对象创建时,只需要传递一个 A 类对象的实参。例如:佣妻棍杨奠启灌沥疚末趾厩赖聊盲吨备平故仑禄婪馁梨始攀第壁爷梗锰僵第四部分编译时多态教学课件第四部分编译时多态教学课件class example public:example(int) example(const char*, int i=0) ;void f(example arg) void mai

66、n() example a = example(1);/ example b = 3;/ example c = Windows!;/ f(3);/ 伞引船硝蚌舍噎禹嗅坛你廊符俩杆楚站茄腿捎蜜练琢湾喝胳萎蛆鞘席算酥第四部分编译时多态教学课件第四部分编译时多态教学课件分析原因: 构造函数 example(int) 将整数 1 显式转换为 example 类对象后赋给 example 类对象 a。 构造函数 example(int) 将整数 3 隐式转换为 example 类对象后赋给 example 类对象 b。 构造函数 example(const char*, int i=0) 将字符串变量

67、 “Windows!” 隐式转换为 example 类对象后赋给 example 类对象 c。 构造函数 example(int) 将整数 3 隐式转换为 example 类对象后作为实参传给函数 f。熊驮泼称脖唆徊溜镐须辜闺洼战晌译振缆纱鄂巾巫骡势苞整吁揭岿絮灵巫第四部分编译时多态教学课件第四部分编译时多态教学课件通过构造函数实现的类型转换可以隐式的,即可以隐含自动完成类型转换,但有时这种隐式转换又不是用户所期望的,甚至是要禁止的。如果要禁止这种隐式转换,可以将会引起隐式转换的构造函数声明为私有成员函数。例如:class vectorvector(int s);/ 构造函数作为私有成员pub

68、lic:vector();static vector make(int s) return s; / 构造函数将参数 s 隐式转换成 vector 对象后返回。;减秩唯浮坯氯胚渐籽秽捧预捧轴亢轮北赫投渗网历瘤揍辱怎茅鼻左域匆群第四部分编译时多态教学课件第四部分编译时多态教学课件main()vector v = vector:make(10);/ 将参数10 显式转换成 vector 对象后赋给用无参数构造/ 函数创建的 vector 对象 v。v = 10;/ 无法将整数 10 隐式转换 vector 对象。v = vector:make(99);/ 将参数 99 显式转换成 vector 对

69、象后赋给用无参数构/ 造函数创建的 vector 对象 v。卖棵离艰悦遮名芹苑耻局锄雕祈借卸辑迷袍柬炉转度寓交煮咙怎腥冈赶廉第四部分编译时多态教学课件第四部分编译时多态教学课件 禁止通过构造函数发生隐式类型转换,还可以使用 explicit 关键字将具有隐式类型转换功能的构造函数声明为只能显式类型转换,即通过这个构造函数进行类型转换时,必须使用强制类型转换表达式。例如:class MyClass int m;public:explicit MyClass(int i = 0);沏宦楼郴院反屈襄赵忙续侠肛瞳狸躯惋铺粗藕粪直秀硷上冗懊杰喳刁键迎第四部分编译时多态教学课件第四部分编译时多态教学课件M

70、yClass:MyClass(int i) m = i; void fun(MyClass); 在这种情况下,函数表达式 fun(5) 将使编译器提示错误信息。要使这个表达式正确,必须使用:fun(MyClass(5);或fun(static_cast(5);实面量让暗椰仲判忽闽而致明暖拎值蓄呢棺谰臃孰亩示累惹名宙含剐纤绽第四部分编译时多态教学课件第四部分编译时多态教学课件4.12.3 类型转换函数类型转换函数 分析通过类构造函数进行类型转换的实现原理和方法,不难看出,类构造函数是不能将自定义类型对象转换成预定义类型对象的。而在实际应用中这种类型转换常常也是十分需要,例如在数学计算中有时需要将

71、一个复数转换为一个实数(取复数的实部值),因此需要一种能实现这种类型转换的方法。类型转换函数不仅可以实现自定义类型对象转换为预定义类型对象,还可以实现两个不同自定义类型对象之间的类型转换。定义类型转换函数的语法如下:狠籍代会陌傍罕押憾晚苍田诣姜锦氖伎膨匝竿谨岳栅篓积拐太轰晕涣缺举第四部分编译时多态教学课件第四部分编译时多态教学课件1 原型 operator type(); type 指定的转换类型,可以是除 void 以外的预 定义类型和任何自定义类型。 注意,类型转换函数既没有参数,也没有返回类 型。例如: class complex double real, imag; public:op

72、erator double(); ;勺腮升炬肮卯膳宇桓新甥檀岔丈跪野平寺姥两妊潘涩灿撬泵尽粥胰语兵卯第四部分编译时多态教学课件第四部分编译时多态教学课件2 定义类名:operator type()return type 类型对象 例如:complex:operator double()return real;谰抢擞篱醒铜篮迄推殃邢姓舰摸少横捌本沛绚焙棚侯贺漾耻充荐膜纵比荡第四部分编译时多态教学课件第四部分编译时多态教学课件3 调用 使用自定义类型转换函数进行类型转换与预定义类 型进行类型转换一样,分为隐式和显式两种转换: 隐式类型转换void fun(double d) complex com

73、;fun(com);/ 复数 com 被转换为实数后作为参数 显式类型转换(type)被转换对象;或 type(被转换对象);例如:complex com;cout (double)com double(com);亥储构馈旗驼拯灰析滇能墙抄邢桶鬃道堑朔矩农布骤钟屯原核塑骂诈脉浩第四部分编译时多态教学课件第四部分编译时多态教学课件例例4-94-9 设计定义一个二进制类 banary,并测试所设计的功能。设计思路: 二进制数在类中的存储 用一个包含 16 个元素的字符串数组 bits16 存放 16 位二进制数码,每个元素值非 0 即 1,并向后对 齐,即最后一个元素 bits15 存放最低位,高

74、位空时 补 0。 传递字符串参数的构造函数 将通过参数传来的字符串中的字符逐个赋值给类对 象中的字符串数组。具体的规则是:协蕾咖岩耪等平骄豆魏柜洁生误缓弟燕蔑矫掂善卿己帛蜜詹洱儿乡质贱够第四部分编译时多态教学课件第四部分编译时多态教学课件 从后向前的顺序赋值; 注意排除参数字符串的结束标志0; 高位缺位必须补0。 传递整型参数的构造函数 采用除 2 余 1算法将通过参数传来的整数转换为二 进制数,算法示意: BEGINfor (字符串数组从后向前的每个字符元素 bitsi) if (整数参数 n % 2 不为 0) then bitsi = 1 else bitsi = 0 endif 整数参

75、数 n 右移一位 endfor END娱梅皑陌比臃葫驰韩腾束超铰芹蠢直俺昏豪劝朔歧苔误铸广焙弃事舆聂层第四部分编译时多态教学课件第四部分编译时多态教学课件 类型转换函数 将二进制类对象(类对象的字符串数组中的二进制 数字串)转换成整数。算法示意: BEGIN整数结果 N = 0for (二进制数码字串中从高到低的每一个字符) if (当前字符 = 1) then 整数 n = 1 else 整数 n = 0 endif N = N * 2 + nendforreturn N END姥囚行阻川娠痕久亿苦晋灭挠必库踞督浑瞬烬森波纠拾抠柒普仗辨亢屡廊第四部分编译时多态教学课件第四部分编译时多态教学课

76、件 重载加运算符 + 两个二进制对象相加后,返回结果二进制对象。使 用友元函数重载加运算符,算法示意: BEGIN进位位整数变量 c = 0结果二进制对象 Sfor (二进制数 A , B 字符串从低到高的每个元素 bitsi) if (A.bitsi 中字符为 1) then 被加数 a = 1 else 被加数 a = 0 endif 贴墅阶酸黄贝悠帽殷胳掂篡撅矽笑墓洼壳抒央贼辣沛禽勾镭顿唬靴刃墟业第四部分编译时多态教学课件第四部分编译时多态教学课件 if (B.bitsi 中字符为 1) then 加数 b = 1 else 加数 b = 0 endif if (a + b + c) %

77、 2 不为 0) then S.bitsi = 1 else S.bitsi = 0 endif if (a + b + c) / 2 不为 0) then c = 1 else c = 0 endifendfor END营挂鼻脉氓描陛客舞诛域欠宫撩辊堪厌雀驭辉弹及埋调滁仆妮散宁鉴蜘手第四部分编译时多态教学课件第四部分编译时多态教学课件 重载减运算符 - 两个二进制对象相减后,返回结果二进制对象。使 用友元函数重载减运算符,算法示意: BEGIN借位位整数变量 c = 0结果二进制对象 Dfor (二进制数 A , B 字符串从低到高的每个元素 bitsi) if (A.bitsi 中字符为

78、1) then 被减数 a = 1 else 被减数 a = 0 endif 零抚世诀糜郧玖兰倾诗彻电衫初龙薯佛肌厌观瓤赶警强召搽根炔仆量固糜第四部分编译时多态教学课件第四部分编译时多态教学课件 if (B.bitsi 中字符为 1) then 减数 b = 1 else 减数 b = 0 endif if (a - b + c) 不为 0) then S.bitsi = 1 else S.bitsi = 0 endif if (a + b + c) 为 -1) 或者 (a 为 0 且 b 为1 且 c 为1) then c = 1 else c = 0 endifendfor END世悦碑赔

79、们隋派厦孜缓锦食辟网温铅苗矛臻峪荔砖主猫给账星归输缴累窄第四部分编译时多态教学课件第四部分编译时多态教学课件类型转换函数的两点说明: 在一个类中可以定义多个类型转换函数。如果一个 类具有多个类型转换函数,则必须显式使用类型转 换函数进行类型转换,否则会引起二义性。 类型转换函数不支持运算表达式中不同类型操作数 的隐式类型转换。因此,如果期望在运算表达式中 不同自定义类型操作数之间、自定义类型操作数与 预定义类型操作数之间也能象不同类型预定义类型 操作数之间那样具有隐式类型转换能力,则可以通 过运算符重载方法实现形式上的“隐式类型转换”, 而不能通过自定义类型的类型转换函数。例如:演闺者来攘烟哉

80、公崔添垃龚匿炼撂澎振壕梳翟逆烟脐耀碌肩袁豌堪欢赋伟第四部分编译时多态教学课件第四部分编译时多态教学课件 class complex double real, imag; public:complex(double r, double i) real = r; imag = I; operator double () return real; friend complex operator + (double, complex&); ; complex operator + (double d, complex& com) return complex(d + com.real, com.ima

81、g); 啸钮鉴潦陌歼魂腻牙味店屿翟孕况骄诌裳诡杏误规笑磊烧矿劣挨跺澡谤壁第四部分编译时多态教学课件第四部分编译时多态教学课件 void func(double d) void main() complex com1(10.5, 20.5), com2;double d = 100.5;com2 = d + com1;/ 重载 “+” 运算符实现隐式类型转换func(com2);/ 类型转换函数实现隐式类型转换 瑶僳怠芒诺潞漂拽稻绎乃沂寿狙豫娘掩灶倦螺裁降虫谩宛摄炒撑倒衷甥次第四部分编译时多态教学课件第四部分编译时多态教学课件 下面通过分析一个 MFC 中 CRect 类的运算符重载函数来感受应

82、该如何考虑是否为一个类定义运算符重载函数,需要定义哪些运算符重载函数和如何定义运算符重载函数。class CRect : public tagRECT ;其中 tagRECT 是一个描述矩形区域的数据结构:typedef struct tagRECT LONG left;LONG top;LONG right;LONG bottom; RECT;CRect 的运算符重载函数分为以下几类:疼六拱炭训委崔决绰夕理乌难霜仰转候奶挥沃到荫馒煌驭良乏掺翌厘沦镍第四部分编译时多态教学课件第四部分编译时多态教学课件 强制类型转换类: operator LPRECT(); operator LPCRECT()

83、 const; 比较运算类: BOOL operator = (const RECT& rect) const; BOOL operator != (const RECT& rect) const; 算术运算类: CRect operator + (POINT point) const; CRect operator - (POINT point) const;皋苑吊戎谴垣瞩敦沟搁勉猿羡翘搐秤续呻饱健硫她蝶整曙霉垮卵豌列集抡第四部分编译时多态教学课件第四部分编译时多态教学课件 CRect operator + (SIZE size) const; CRect operator - (SIZE

84、size) const; void operator += (POINT point); void operator -= (POINT point); void operator += (SIZE size); void operator -= (SIZE size); void operator += (LPCRECT lpRect); void operator -= (LPCRECT lpRect); CRect operator + (LPCRECT lpRect) const; CRect operator - (LPCRECT lpRect) const;茨迹好撇掖桔傍差塑屑棚胆

85、矛部蕊嘶拉予述碳壕砍匡捻授羞桨肮苟女挤扦第四部分编译时多态教学课件第四部分编译时多态教学课件 位运算类: CRect operator & (const RECT& rect2) const; CRect operator | (const RECT& rect2) const; void operator &= (const RECT& rect); void operator |= (const RECT& rect); 赋值运算类: void operator = (const RECT& srcRect);返回怠绍豆挞腑陈挎站窟纯霸力皆廖恐耀辅荫殴查武健呼浦锹胀译刨瀑慧训赊第四部分编译时多态教学课件第四部分编译时多态教学课件

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 建筑/环境 > 施工组织

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号