内容 运算符重载为类的成员函数 运算符重载为类的友元函数 双目运算符的重载 单目运算符的重载 流运算符的重载 转换构造函数 类型转换函数.

Slides:



Advertisements
Similar presentations
如何學好數學? 黃駿耀老師
Advertisements

辅助核算 3.5.
10 郑和远航.
三个偶像的故事和功绩 ——第12课 明清时期的反侵略斗争 董飞燕.
捣蛋鬼历险记 初一四班 孙嘉佑小组.
中國歷史 明代之患禍及民變.
10 郑和远航 郑和 郑和,1371年生于云南昆阳州(今昆明晋宁县)一个信奉伊斯兰教的回族家庭,原名马和,小字三宝,十一岁时在明太祖朱元璋发动的统一云南的战争中被俘进宫,后当朱元璋四子燕王朱棣的近侍。1403年朱棣登基,史称明成祖。次年正月初一,朱棣念他有勇有谋,屡立奇功,便赐姓“郑”,改称郑和,并提拔为内宫太监,于永乐三年(1405年7月11日)率领庞大船队首次出使西洋。自1405年到1433年,漫长的28年间,郑和船队历经亚非三十余国,涉十万余里,与各国建立了政治,经济,文化的联系,完成了七下西洋的伟
明清 抗击外国侵略的英勇斗争 雅克萨反击战(俄) 戚继光抗倭(日) 郑成功收复台湾(荷兰) 荷兰 俄 罗 斯 日 本 台湾 沙 俄 入 侵
戚继光抗倭.
刑事訴訟法 授課人:林俊益副教授 時間:95.9.~96.6..
妩媚人生 云 计 算 与 大规模数据并行处理技术 黄 宜 华 南 京 大 学 计算机科学与技术系 软件新技术国家重点实验室 妩媚人生 妩媚人生
第16 课 中外的交往与冲突 授课人:鲍婷.
历史上的中日关系.
云南外事外语职业学院 入党积极分子培训 赵田甜.
第四章 清代臺灣的社會文化變遷 第一節 移墾社會的形成
認識食品中毒 一、什麼是食品中毒? 二人或二人以上攝取相同的食品而發生相似的症狀,並且自可疑的食餘檢體及患者糞便、嘔吐物、血液等人體檢體,或者其它有關環境檢體(如空氣、水、土壤等)中分離出相同類型(如血清型、噬菌 體型)的致病原因,則稱為一件“食品中毒”。 但如因攝食肉毒桿菌毒素或急性化學性中毒而引起死亡,即使只有一人,也視為一件“食品中毒”。
題目:四大古文明 班級:六年八 班 組員:賴宣光.游家齊.陳羿文 吳佳芬.許淑婷.許芳瑜..
食 物 中 毒.
琦君 《髻》 S 康倩瑜.
眼乾乾唔使慌.
滑膜皱襞综合征.
“公平”是最热的关键词 1、胡锦涛首次进行“总动员”,提出“在促进发展的同时,把维护社会公平放到更加突出的位置” 。
贵州省公务员面试 备考指导 中公教育 面试讲师 刘运龙.
外 套 各式領型與變化 武 玫 莉 製 作.
第4节 人体对食物的消化吸收.
陈冤之魅,心鬼之泪 ——雾里探花 《东方快车谋杀案》 By第二小组.
高考作文等级评分标准/发展等级10分 深刻 丰富 有文采 有创意 ①透过现象 深入本质 ②揭示问题 产生的原因 ③观点具有 启发作用
文明礼仪在我心 文明礼仪在我心.
第10课 社会生活的变迁.
故事会 盘古开天劈地 在很久很久以前,天地可不象我们现在看到的这样————天高高的在上面,地在我们的脚下,中间隔着几千几万米远。那个时候的天地就象是一个包在大黑壳里的鸡蛋,混混沌沌的,什么也看不清。人们走路都得弯着腰,耕田打猎都很不方便,因为一不小心抬个头,就会碰到天,惹它生气,接着就会招来狂风暴雨。因此所有的植物也都长不高,所以结的粮食和果实都很少,根本就不够大家吃。还经常会发生饿死人的事情。
面向三农,拓宽信息渠道 辐射千村,服务百万农民
三招 让孩子爱上阅读 主讲人:芝莺妈妈 2012年10月19日.
FUZHUANGZHITUYANGBANZHIZUO
如何挑選吳郭魚 嗨~ 餐旅二乙 4a2m0105 白妤潔 4a2m0122 何姿瑩.
学校春季呼吸道传染病预防知识 连云港市疾病预防控制中心
服裝整理概論.
印染纺织类艺术.
创业计划书的编写.
创业计划书撰写.
第九章 进行充分调研 选择自主创业.
香溢饺子馆创业计划书.
第三章 中国的民族民俗 第一节 概论 第二节 汉族 第三节 满族 蒙古族 维吾尔族 回族 朝鲜族 第四节 壮族 土家族 苗族 黎族
第 4 章 投资银行: 基于资本市场的主业架构.
创业数字图书馆.
中国管理科学发展探索 成思危 2006年8月18日于上海复旦大学.
“四文”交融,虚实并举,打造具有鲜明职教特色的校园文化 ——江苏省扬州商务高等职业学校校园文化建设汇报
103年度高職優質化輔助方案計畫申辦及輔導訪視說明會
“十二五”科技发展思路 与科技计划管理 科技部发展计划司 刘敏 2012年9月.
社区妇幼保健工作 江东区妇幼保健院 胡波瑛.
人生不要太圓滿 ◎ 張忠謀.
导致羊水过少的五大因素.
胎教.
怎样进行一次宣讲 何惠玲.
第三课 中国共产党的历程.
[聚會時,請將傳呼機和手提電話關掉,多謝合作]
规范母婴保健服务 努力降低孕产妇死亡率 市卫生局基妇科 朱静.
中国地质科学院矿产资源研究所 财务报账培训
白天的月亮 想與日爭輝 人生不要太圓滿 文字取自於:張忠謀 攝於陽明山 阿道的攝影工作坊.
第十章(上) 实现中华民族的伟大复兴.
营养要均衡.
ㄩ.
高中新课程历史必修(Ⅰ) 教材比较研究 四川师范大学历史文化学院教授 陈 辉 教育部2009普通高中历史课改远程研修资料.
十年职业生涯规划 —— 年 姓名:刘娟 学号:.
主考官眼中的面试 ——面试主考官教你备战2016年国考面试 主讲老师:李海鹏.
国内知名高校 医学院(部、中心) 院系及附属医院设置情况 调研报告
財務報表分析 授課教師:陳依婷.
第六章 可供出售金融资产 一、可供出售金融资产的概念和特征 二、可供出售金融资产的核算.
主讲人:刘文波 (四会国税 政策法规股) 2014年4月
智慧宁波 智慧财税 . 宁波市地方税务局.
第六模块礼仪文书写作 第一节求职信、应聘信 QIUZHIXINYINGPINXIN.
Presentation transcript:

运算符重载 潘荣江 panrj@sdu.edu.cn 山东大学

内容 运算符重载为类的成员函数 运算符重载为类的友元函数 双目运算符的重载 单目运算符的重载 流运算符的重载 转换构造函数 类型转换函数

复习: 类(class) #include<iostream> using namespace std; class Complex //定义Complex类 { public: Complex(){real=0; imag=0;} //定义构造函数 Complex(double r, double i){real=r;imag=i;} //构造函数重载 Complex complex_add(Complex &c2); //声明复数相加函数 void display(); //声明输出函数 private: double real; //实部 double imag; //虚部 };

Complex Complex∷complex_add(Complex &c2) //定义复数相加函数 c.real=real+c2.real; c.imag=imag+c2.imag; return c; } void Complex∷display() //定义输出函数 { cout<<"("<<real<<","<<imag<<"i)"<<endl; } int main() { Complex c1(3,4),c2(5,-10),c3; //定义3个复数对象 c3=c1.complex_add(c2); //调用复数相加函数 cout<<"c1="; c1.display(); //输出c1的值 cout<<"c2="; c2.display(); //输出c2的值 cout<<"c1+c2="; c3.display(); //输出c3的值 return 0; } 运行结果: c1=(3,4i) c2=(5,-10i) c1+c2=(8,-6i)

函数重载 (function overloading) 函数重载是指完成不同功能的函数可以具有相同的函数名。 C++的编译器根据函数的实参来确定应该调用哪一个函数。 1、定义的重载函数必须具有不同的参数个数,或不同的参数类型。编译系统根据不同的参数去调用不同的重载函数,实现不同的功能。 2、仅返回值不同时,不能定义为重载函数。 int fun(int a, int b) { return a+b; } void main(void) { cout<<fun(3,5)<<endl; cout<<fun(5)<<endl; } 8 int fun (int a) { return a*a; } 25

系统自动识别int、float等数据类型的+ 运算符重载(operator overloading) int sum,a=3,b=2; (int)=(int) + (int) sum=a+b; 系统自动识别int、float等数据类型的+ float add, x=3.2, y=2.5; add=x+y; (float)=(float) + (float) Complex c1(3,4), c2(5,-10), c3; //定义3个复数对象 c3=c1 + c2; //8-6i 编译系统中的运算符“+”本身不能做Complex的“+”运算,必须重新定义“+”运算符,这种重新定义的过程称为运算符的重载。

运算符重载实现两个复数相加 两对象+,必须重新定义+ 运算符重载赋予已有的运算符多重含义。C++通过重新定义运算符,使它能够用于特定的对象,执行特定的功能

//也可以利用无名对象 Complex Complex∷operator+(Complex &c2) //定义重载运算符+的函数 { return Complex(real+c2.real, imag+c2.imag); } 将运算符+重载为类的成员函数后, C++编译系统将程序中的表达式 c1+c2 解释为 c1.operator+(c2) //其中c1和c2是Complex类的对象,即以c2为实参调用c1的运算符重载函数operator+(Complex &c2), 得到两个复数之和。 c3 = c1+c2; // 可以 c3 = 3 + c2; //能这样做吗? c3 = Complex(3,0) + c2;

运算符的重载体现了OOP技术的多态性,且同一运算符根据不同的运算对象可以完成不同的操作。 为了重载运算符,必须定义一个函数,告诉编译器,遇到这个重载运算符就调用该函数,由这个函数来完成该运算符应该完成的操作,这种函数称为运算符重载函数,它通常是类的成员函数或者是友元函数。运算符的操作数通常也应该是类的对象。 运算符的重载体现了OOP技术的多态性,且同一运算符根据不同的运算对象可以完成不同的操作。 运算符重载对C++有重要的意义。 本来C++ 提供的运算符只能用于C++的标准数据类型,不能用于用户定义的类对象,影响了类和对象的使用。 C++不是为类对象另外定义一批新的运算符,而是允许重载现有的运算符,使这些简单易用、众所周知的运算符能够直接用于类对象。运算符重载使C++具有更强大的功能、更好的可扩充性和适应性。

A operator + (A &); 运算符重载函数的格式 { 函数体 } 运算的对象 关键字 函数名 运算的对象 返回类型 A operator + (A &); //重载了类A的“+”运算符 其中:operator是定义运算符重载函数的关键字,它与其后的运算符一起构成函数名。

利用函数完成了加法运算 没有使用运算符重载的例子 class A { int i; public: A(int a=0) { i=a; } void Show(void){ cout<<"i="<<i<<endl; } A AddA(A &a) //利用函数进行对象之间的运算 { return A(i+a.i); } }; void main(void) { A a1(10),a2(20),a3; a1.Show (); a2.Show (); // a3=a1+a2; //不可直接运算 a3=a1.ddA(a2); //调用专门的功能函数 a3.Show (); } 利用函数完成了加法运算

运算符重载的例子 class A { int i; public:A(int a=0){ i=a; } void Show(void){ cout<<"i="<<i<<endl; } A AddA(A &a) //利用函数进行对象之间的运算 { return A(i+a.i); } A operator +(A &a) //重载运算符+ { A t; t.i=i+a.i; return t; } }; void main(void) { A a1(10),a2(20),a3; a1.Show (); a2.Show (); a3=a1+a2; //重新解释了加法,可以直接进行对象的运算 a3=a1.AddA(a2); //调用专门的功能函数 a3.Show (); } 相当于a3=a1.operator+(a2)

A AddA(A &a) { return A(i+a.i); } A operator +(A &a) { A t; t.i=i+a.i; 重载运算符与一般函数的比较: 相同:1)均为类的成员函数;2)实现同一功能 返回值 函数名 形参 返回值 函数名 形参列表 A AddA(A &a) { return A(i+a.i); } A operator +(A &a) { A t; t.i=i+a.i; return t; } 函数调用: A3=a1.AddA(a2); 函数调用: 由对象a1调用 a3=a1+a2; a3=a1.operator+(a2); 由对象a1调用

重载运算符的规则 只能对C++中已有的运算符进行重载。 在C++中允许重载的运算符如下。

C++中不能重载的运算符只有5个:. (成员访问运算符). (成员指针访问运算符) ∷ (域运算符) sizeof (长度运算符) 前两个运算符不能重载是为了保证访问成员的功能不能被改变。 域运算符和sizeof运算符的运算对象是类型而不是变量或一般表达式,不具重载的特征。 重载不能改变运算符的优先级、结合性、运算对象(即操作数)的个数。 重载运算符的函数不能有默认的参数,否则就改变了运算符参数的个数。

r4=r1+r2+r3; (r1+r2); (r1+r2)+r3; r4=r1+(r2+r3); (r2+r3); r1+(r2+r3); class room{ float Length; float Wide; public: room(float a=0.0,float b=0.0){ Length=a; Wide=b; } void Show(void){cout<<"Length="<<Length<<'\t'<<"Wide="<<Wide<<endl;} void ShowArea(void){ cout<<"Area="<<Length*Wide<<endl; } room operator+(room &);//重载运算符+,函数原型 }; room room::operator + (room &r) //重载运算符函数 { room rr; rr.Length =Length+r.Length; rr.Wide =Wide+r.Wide ; return rr; } void main(void) { room r1(3,2),r2(1,4), r3,r4; r1.Show (); r2.Show (); r3=r1+r2; r3.Show (); r4=r1+r2+r3; r4.Show (); r4=r1+r2+r3; (r1+r2); (r1+r2)+r3; r4=r1+(r2+r3); (r2+r3); r1+(r2+r3); 运算符的优先级和结合律是不能改变的

重载的运算符必须和用户定义的自定义类型的对象一起使用,其参数至少应有一个是类对象(或类对象的引用)。也就是说,参数不能全部是C++的标准类型,以防止用户修改用于标准类型数据的运算符的性质。 用于类对象的运算符一般必须重载,但有两个运算符不需用户重载。 ①赋值运算符(=)可以用于每一个类对象,利用它在同类对象之间相互赋值。 ②地址运算符&也不必重载,它能返回类对象在内存中的起始地址。 应当使重载运算符的功能类似于该运算符作用于标准类型数据时所实现的功能。

运算符重载函数作为类成员函数 当用成员函数实现运算符的重载时,运算符重载函数的参数只能有二种情况:没有参数或带有一个参数。 对于只有一个操作数的运算符(如++),在重载这种运算符时,通常不能有参数; 对于有二个操作数的运算符,只能带有一个参数。这个参数可以是对象、对象的引用或其它类型的参数。

运算符重载为类成员函数时,是由一个操作数调用函数,函数的实参只有一个或没有。 A a ,b , c; c=a+b; 实际上是c=a.operator+(b); c=++a; 实际上是c=a.operator++( ); c+=a; 实际上是c.operator+=( a ); 用成员函数实现运算符的重载时,运算符的左操作数为当前对象,这是一个隐含的参数,要用到隐含的this指针。 运算符重载函数不能定义为静态的成员函数,因为静态的成员函数中没有this指针。

没有返回值,函数类型为void。 class A { int i; public:A(int a=0){ i=a; } void Show(void){ cout<<"i="<<i<<endl; } A operator +(A &a) //重载运算符+ { A t; t.i=i+a.i; return t; } void operator+=(A &a) { i=i+a.i; } }; void main(void) { A a1(10),a2(20),a3; a1.Show (); a2.Show (); a3=a1+a2; a1+=a2; a3.Show (); } 没有返回值,函数类型为void。 相当于a3=a1.operator+(a2) 相当于a1.operator+=(a2)

运算符重载为类的友元函数 友元函数是在类外的普通函数,与一般函数的区别是可以调用类中的私有或保护数据。 将运算符的重载函数定义为友元函数,参与运算的对象全部成为函数参数。 A a ,b , c; c=a+b; 实际上是 c=operator+(a, b); c=++a; 实际上是 c=operator++(a); c+=a; 实际上是 operator+=(c, a);

对单目运算符,友元函数有一个参数。 对双目运算符,友元函数有2个参数。 格式为: friend <类型说明> operator<运算符>(<参数表>) {......} c=a+b; // c=operator+( a, b) friend A operator + (A &a, A &b) {.....}

}

运算符重载函数可以是类的成员函数,也可以是类的友元函数,还可以是既非类的成员函数也不是友元函数的普通函数。 只有在极少的情况下才使用既不是类的成员函数也不是友元函数的普通函数,原因是普通函数不能直接访问类的私有成员。 如果将运算符重载函数作为成员函数,可以通过this指针自由地访问本类的数据成员,少写一个函数的参数。但必须要求运算表达式第一个参数(即运算符左侧的操作数)是一个类对象,而且与运算符函数的类型相同,必须通过类的对象去调用该类的成员函数。 如:表达式c1+c2中第一个参数c1是Complex类对象,这是正确的。如果c1不是Complex类,就无法通过隐式this指针访问Complex类的成员了。

如想将一个复数和一个整数相加,如c1+i, 可以将 运算符重载函数作为成员函数,如下面的形式: Complex Complex∷operator+(int i) //运算符重载函数作为Complex 类的成员函数 {return Complex(real+i,imag);} 注意在表达式中重载的运算符“+”左侧应为Complex类的对象,如 c3=c2+i; 不能写成 c3=i+c2; //运算符“+”的左侧不是类对象,编译出错 如果出于某种考虑,要求在使用重载运算符时运算符左侧的操作数是整型量(如表达式i+c2, 运算符左侧的操作数i是整数),这时无法利用前面定义的重载运算符,因为无法调用i.operator+函数。 如果运算符左侧的操作数属于C++标准类型(如int)或是一个其他类的对象,则运算符重载函数不能作为成员函数,只能作为非成员函数。如果函数需要访问类的私有成员,则必须声明为友元函数。

在Complex类中声明: friend Complex operator+(int i,Complex &c); //第一个参数可以不是类对象 在类外定义友元函数: Complex operator+(int i, Complex &c) //运算符重载函数不是成员函数 {return Complex(i+c.real,c.imag);} 将双目运算符重载为友元函数时,在函数的形参表列中必须有两个参数,不能省略,形参的顺序任意,不要求第一个参数必须为类对象。但在使用运 算符的表达式中,要求运算符左侧的操作数与函数第一个参数对应,运算符右侧的操作数与函数的第二个参数对应。 c3=i+c2; //正确,类型匹配 c3=c2+i; //错误,类型不匹配 数学上的交换律在此不适用。如果希望适用交换律,则应再重载一次运算符“+”。 Complex operator+(Complex &c, int i) //此时第一个参数为类对象 { return Complex(i+c.real,c.imag); } 这样,使用表达式i+c2和c2+i都合法。

C++规定,赋值运算符=、下标运算符[]、函数调用运算符()、成员运算符-> 必须定义为类的成员函数。 流插入运算符“<<”、流提取运算符“>>”、类型转换运算符不能定义为类的成员函数,只能作为友元函数。 一般将单目运算符和复合运算符重载为成员函数。 一般将双目运算符重载为友元函数。

双目运算符的重载 双目运算符(或称二元运算符)是C++中最常用的运算符。双目运算符有两个操作数,通常在运算符的左右两侧,如3+5,a=b,i<10等。 如果要重载双目运算符B 为类成员函数,使之能够实现表达式 oprd1 B oprd2,其中 oprd1 为A 类对象,则 B 应被重载为 A 类的成员函数,形参类型应该是 oprd2 所属的类型。 经重载后,表达式 oprd1 B oprd2 相当于 oprd1.operator B(oprd2)

指导思想: 先搭框架,逐步扩充,由简到繁,最后完善。

单目运算符的重载 只有一个操作数的运算符为单目运算符,常用的有: !a, -b, &c, *p ,++,--。 A a; ++a; a++; A a, b; b=++a; b=a++; 虽然运算后对象a的值一致,但先自加或后自加的函数的返回值不一致,必须在重载时予以区分。

A a, b; b=++a; b=a++; A operator ++( ){ .... } ++为前置运算时,运算符重载函数的一般格式为: <type> operator ++( ) { ...... } ++为后置运算时,运算符重载函数的一般格式为: <type> operator ++(int) A a, b; b=++a; b=a++; A operator ++( ){ .... } A operator ++(int){ .... }

例 有一个Time类,包含数据成员minute(分)和sec(秒),模拟秒表,每次走一秒,满60秒进一分钟,此时秒又从0开始算。要求输出分和秒的值。 #include <iostream> using namespace std; class Time { public: Time( ){minute=0;sec=0;} //默认构造函数 Time(int m,int s):minute(m),sec(s){ } //构造函数重载 Time operator++( ); //声明前置自增运算符“++”重载函数 Time operator++(int); //声明后置自增运算符“++”重载函数 void display( ){ cout<<minute<<″:″<<sec<<endl; } //定义输出时间函数 private: int minute; int sec; };

Time Time∷operator++( ) //定义前置自增运算符“++”重载函数 { if(++sec>=60) { sec-=60; ++minute; } return *this; //返回自加后的当前对象 } Time Time∷operator++(int) //定义后置自增运算符“++”重载函数 { Time temp(*this); sec++; if(sec>=60) { sec-=60; ++minute; } return temp; //返回的是自加前的对象 }

int main( ) { Time time1(34,59),time2; cout<<″ time1 :″; time1.display( ); ++time1; cout<<″++time1:″; time1.display( ); time2=time1++; //将自加前的对象的值赋给time2 cout<<″time1++:″; time1.display( ); cout<<″ time2 :″; time2.display( ); //输出time2对象的值 }

A operator ++(A a, int){ .... } ++为前置运算时,友元运算符重载函数的一般格式为: A operator ++(A &a) { ......;} ++为后置运算时,友元运算符重载函数的一般格式为: A operator ++(A &a, int) A a, b; b=++a; b=a++; A operator ++( A a ){ .... } A operator ++(A a, int){ .... }

相当于a3=operator++(a1,int) class A { int i; public: A(int a=0) { i=a; } void Show(void) { cout<<"i="<<i<<endl; } A operator++(A &a){ a.i++; return a;} A operator++(A &a, int n) { A t; t.i=a.i; a.i++; return t; } }; void main(void) { A a1(10),a2,a3; a2=++a1; a3=a1++; a2.Show(); a3.Show (); } 相当于a2=operator++(a1) 相当于a3=operator++(a1,int)

流运算符的重载 C++的流插入运算符“<<”和流提取运算符“>>”是C++在类库中提供的,所有C++编译系统都在类库中提供输入流类istream和输出流类ostream。 cin和cout分别是istream类和ostream类的对象。在类库提供的头文件中已经对“<<”和“>>”进行了重载,作为流插入运算符和流提取运算符,能用来输出和输入C++标准类型的数据,用#include <iostream>包含到自己的程序文件中。 用户自己定义的类型的数据,不能直接用“<<”和“>>”来输出和输入。如果想用它们输出和输入自己声明的类型的数据,必须对它们重载。对“<<”和“>>”重载的函数形式如下: istream & operator >> (istream &,自定义类 &); ostream & operator << (ostream &,自定义类 &); 重载“>>”的函数的第一个参数和函数的类型都必须是istream&类型,第二个参数是要进行输入操作的类。 重载“<<”的函数的第一个参数和函数的类型都必须是ostream&类型,第二个参数是要进行输出操作的类。 只能将重载“>>”和“<<”的函数作为友元函数或普通的函数,而不能将它们定义为成员函数。(why?)

用重载的“<<”输出复数。 #include <iostream> using namespace std; class Complex {public: Complex( ){real=0;imag=0;} Complex(double r,double i) {real=r;imag=i;} Complex operator + (Complex &c2); //运算符“+”重载为成员函数 friend ostream& operator << (ostream&,Complex&); //“<<”重载为友元函数 private: double real; double imag; }; Complex Complex∷operator + (Complex &c2) //定义运算符“+”重载函数 { return Complex(real+c2.real,imag+c2.imag);} ostream& operator << (ostream& output, Complex& c) //定义运算符“<<”重载函数 { output<<″(″<<c.real<<″+″<<c.imag<<″i)″<<endl; return output; }

int main( ) { Complex c1(2,4),c2(6,10),c3; c3=c1+c2; cout<<c3; return 0; } 运行结果为:(8+14i) 编译系统把“cout<<c3”解释为operator<<(cout,c3) return output的作用是什么? 返回cout的当前值,以便连续输出 。output是ostream类的对象,它是实参cout的引用,也就是cout通过传送地址给output,它们二者共享同一段存储单元,或者说output是cout的别名。return output就是return cout,将输出流cout的现状返回,即保留输出流的现状。 cout<<c3<<c2; (cout<<c3)<<c2;

增加重载流提取运算符“>>”,用cin>>输入复数,用cout<<输出复数。 #include <iostream> using namespace std; class Complex {public: friend ostream& operator << (ostream&,Complex&); //声明重载运算符“<<” friend istream& operator >> (istream&,Complex&); //声明重载运算符“>>” private: double real; double imag; }; ostream& operator << (ostream& output,Complex& c) //定义重载运算符“<<” { output<<″(″<<c.real<<″+″<<c.imag<<″i)″; return output; } istream& operator >> (istream& input,Complex& c) //定义重载运算符“>>” { cout<<″input real part and imaginary part of complex number:″; input>>c.real>>c.imag; return input; }

int main( ) { Complex c1,c2; cin>>c1>>c2; cout<<″c1=″<<c1<<endl; cout<<″c2=″<<c2<<endl; return 0; } 运行情况如下: input real part and imaginary part of complex number: 3 6↙ input real part and imaginary part of complex number: 4 10↙ c1=(3+6i) c2=(4+10i)

虚部如果是负数,就不理想。 input real part and imaginary part of complex number:3 6↙ input real part and imaginary part of complex number:4 -10↙ c1=(3+6i) c2=(4+-10i) 可对程序作必要的修改,将重载运算符“<<”函数修改如下: ostream& operator << (ostream& output,Complex& c) { output<<″(″<<c.real; if(c.imag>=0) output<<″+″; //虚部为正数时,在虚部前加“+”号 output<<c.imag<<″i)″<<endl; //虚部为负数时,在虚部前不加“+”号 return output; } 这样,运行时输出的最后一行为c2=(4-10i)。

标准类型数据间的转换 有些转换是由C++编译系统自动完成的,用户不需干预。这种转换称为隐式类型转换。 int i = 6; i = 7.5 + i; C++还提供显式类型转换,在程序中指定将一种指定的数据转换成另一指定的类型,其形式为 类型名(数据) 如 int(89.5), 其作用是将89.5转换为整型数89

转换构造函数 转换构造函数(conversion constructor function)的作用是将一个其他类型的数据转换成一个类的对象。 •默认构造函数。 Complex( ); //没有参数 •用于初始化的构造函数。 Complex(double r,double i); //形参表列中一般有两个以上参数 •用于复制对象的复制构造函数。 Complex (Complex &c); //形参是本类对象的引用 •转换构造函数。转换构造函数只有一个形参,如 Complex(double r) {real=r; imag=0;} 其作用是将double型的参数r转换成Complex类的对象,将r作为复数的实部,虚部为0。 用户可以根据需要定义转换构造函数,在函数体中告诉编译系统怎样去进行转换。在类体中,可以有转换构造函数,也可以没有转换构造函数,视需要而定。以上几种构造函数可以同时出现在同一个类中,它们是构造函数的重载。编译系统会根据建立对象时给出的实参的个数与类型 选择形参与之匹配的构造函数。

在该类的作用域内可以用以下形式进行类型转换: 类名(指定类型的数据) 就可以将指定类型的数据转换为此类的对象。 Complex c1(3.0); Complex c2= Complex(3.0); //先建立一个无名对象,然后复制 Complex c3= 3.0; Complex c = c1 + Complex(3.0); 不仅可以将一个标准类型数据转换成类对象,也可以将另一个类的对象转换成类对象。 如可以将一个学生类对象转换为教师类对象,可以在Teacher类中写出下面的转换构造函数: Teacher(Student& s) { num=s.num; strcpy(name,s.name); sex=s.sex; } 但应注意: 对象s中的num,name,sex必须是公用成员,否则不能被类外引用。

类型转换函数 类型转换函数是在类中定义一个成员函数,将类的对象转换为另外一种类型的数据。 利用转换函数将类A的对象a转换成某种数据类型 class A { float x, y; public: A(float a, float b){ x=a; y=b; } }; void main(void) { A a(2,3); cout<<a<<endl; } 利用转换函数将类A的对象a转换成某种数据类型 错误!类的对象不能直接输出

A float 1. 转换函数必须是类的成员函数,不能是友元函数。 格式为: ClassName :: operator <type>( ) {.........} 类名 关键字 欲转换类型 具体的转换算法 2. 转换函数的调用是隐含的,没有参数。转换函数的操作数是对象。 A :: operator float ( ) { return x+y; } 转换算法自己定义

class A { int i; public:public: A(int a=0) { i=a; } void Show(void) { cout<<"i="<<i<<endl; } operator int( ){ return i; } }; void main(void) { A a1(10), a2(20); cout<<a1<<endl; // 可以直接输出c,因为已经进行类型转换 cout<<a2<<endl; }

class Complex{ float Real,Image; public: Complex(float real=0, float image=0) { Real=real; Image=image; } void Show(void) {cout<<"Real="<<Real<<'\t'<<"Image="<<Image<<endl; } operator float(); //成员函数,定义类转换 Complex->float }; Complex::operator float () { return Real*Real+Image*Image;} void main(void) { Complex c(10,20); c.Show (); cout<<c<<endl;//可以直接输出c,因为已经进行类型转换 }

赋值运算符与赋值运算符重载 “=” 同类型的对象间可以相互赋值,等同于对象的各个成员的一一赋值。 A a(2,3), b; b=a; 但当对象的成员中使用了动态的数据类型时(用new开辟空间),就不能直接相互赋值,否则在程序的执行期间会出现运行错误。

A(char *s ){ ps =new char [strlen(s)+1]; strcpy(ps,s);} class A{ char *ps; public: A( ){ ps=0;} A(char *s ){ ps =new char [strlen(s)+1]; strcpy(ps,s);} ~A( ){ if (ps) delete [] ps;} void Show(void) { cout<<ps<<endl;} }; void main(void ) { A s1("China!"),s2("Computer!"); s1.Show(); s2.Show(); s2=s1; } s1 ps “China” s2 ps "Computer" s2.ps=s1.ps //相当于 s2.ps=s1.ps; 首先析构s2 接着析构s1出错

这时,利用编译系统的默认赋值无法正确运行程序,必须重载赋值运算符“=”,即重新定义“=”。 格式为: <函数类型> <ClassName>::operator=(<参数表>) 赋值运算符必须重载为成员函数。 函数名 函数参数 成员函数作用域 A A:: operator = (A &a) 左操作符调用右操作符 函数返回值类型 b.operator=(a); b=a;

class A{ char *ps; public: A( ){ ps=0;} A(char *s ){ ps =new char [strlen(s)+1]; strcpy(ps,s);} ~A( ){ if (ps) delete [] ps;} void Show(void) { cout<<ps<<endl;} A& operator=(A &b); }; void main(void ) { A s1("China!"),s2("Computer!"); s1.Show(); s2.Show(); s2=s1; } 重新定义“=”

A & A::operator = ( A &b)//重载赋值运算符 { if ( ps ) delete [ ] ps; if ( b.ps) { ps = new char [ strlen(b.ps)+1]; strcpy( ps, b.ps); } else ps =0; return *this; s2=s1; s2.operator=(s1); s1 ps “China” s2 ps “China” “Computer” 返回同种类型的引用适合于连等。 s3=s2=s1;

class A{ char *ps; public: A( ){ ps=0;} A(char *s ){ ps =new char [strlen(s)+1]; strcpy(ps,s); } ~A( ){ if (ps) delete[] ps;} char *GetS( ) {return ps;} A & operator = ( A &b);//重载赋值运算符 }; A &A::operator = ( A &b)//重载赋值运算符 { if ( ps ) delete [ ] ps; if ( b.ps) { ps = new char [ strlen(b.ps)+1]; strcpy( ps, b.ps); } else ps =0; return *this; } void main(void ) { A s1("China!"),s2("Computer!"); s2=s1; cout <<"s1= "<< s1.GetS()<<'\t'; cout <<"s2= "<< s2.GetS()<<'\n'; 重新开辟内存 s2.ps重新开辟内存,存放“China”