版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、C+语言程序设计,杨国兴 张东玲 彭涛,中国水利水电出版社,第6章 多态性,6.1 运算符重载 6.2 运算符重载为类的成员函数 6.3 运算符重载为类的友元函数 6.4 虚函数,6.1 运算符重载,6.1.1 问题的提出 例4.3的复数类 #include iostream.h class CComplex private: double real; double imag; public: CComplex(double r, double i); void Print(); CComplex Add(CComplex c); CComplex Sub(CComplex c); ;,第6章
2、 多态性,CComplex CComplex:Add(CComplex c) CComplex temp; temp.real = real + c.real; temp.imag = imag + c.imag; return temp; CComplex CComplex:Sub(CComplex c) CComplex temp; temp.real = real - c.real; temp.imag = imag - c.imag; return temp; ,6.1 运算符重载,6.1.1 问题的提出(续一) void main(void) CComplex a(1, 2), b(
3、3.0, 4.0), c,d; c = a.Add(b); d = a.Sub(b); cout c = ; c.Print(); cout d = ; d.Print(); ,第6章 多态性,运算符重载:运算符重载的实质就是对已有的运算符赋予多重含义,使同一个运算符 作用于不同类型的数据时,产生不同的行为。运算符重载的实质就是函数重载。,例6.1 用运算符实现复数的加减运算,#include iostream using namespace std; class CComplex private: double real; double imag; public: CComplex(doub
4、le r=0, double i=0); void Print(); CComplex operator +(CComplex c); CComplex operator -(CComplex c); ; CComplex:CComplex (double r, double i) real = r; imag = i; ,第6章 多态性,例6.1 (续一),void CComplex:Print() cout ( real , imag ) endl; CComplex CComplex:operator +(CComplex c) CComplex temp; temp.real = re
5、al + c.real; temp.imag = imag + c.imag; return temp; CComplex CComplex:operator -(CComplex c) CComplex temp; temp.real = real - c.real; temp.imag = imag - c.imag; return temp; ,第6章 多态性,例6.1 (续二),void main(void) CComplex a(1, 2), b(3.0, 4.0), c,d; c = a+b; d = a-b; cout c = ; c.Print(); cout d = ; d.
6、Print(); ,第6章 多态性,该语句相当于对函数operator +(CComplex c)的调用:“c=a.operator +(b)”,实现两个复数的加法运算。,程序运行结果为: c = (4, 6) d = (-2, -2),6.1 运算符重载,6.1.2 运算符重载的格式与规则 1. 运算符重载的格式 运算符重载为类的成员函数 运算符重载为类的友元函数 运算符重载的为类的成员函数,在类中声明的格式为: 函数类型 operator 运算符(参数表); 定义该函数的格式: 函数类型 类名:operator 运算符(参数表) 函数体; 也可以将重载运算符函数的定义直接写在类中。,第6章
7、 多态性,6.1 运算符重载,6.1.2 运算符重载的格式与规则(续) 2. 运算符重载的规则 (1)除“.”、“*”、“:”、“?:”和“sizeof”等几个运算符不能重载外,C+中几乎所有的运算符都可以重载。 (2)运算符被重载后,其优先级和结合性不会改变。 (3)不能改变运算符操作对象的个数。,第6章 多态性,6.2 运算符重载为类的成员函数,6.2.1 双目运算符重载 双目运算符,如果重载为类的成员函数,其参数为一个,即比运算对象少一个。 例6.2 复数的乘法运算,在上例的基础上添加乘法运算符重载函数。复数类乘法运算的定义如下: (a+bi)*(x+yi)= a*x-b*y + (a*
8、y + b*x)i,第6章 多态性,例6.2 复数乘法运算源程序,#include iostream using namespace std; class CComplex private: double real; double imag; public: CComplex(double r=0, double i=0); void Print(); CComplex operator +(CComplex c); CComplex operator -(CComplex c); CComplex operator *(CComplex c); ; CComplex:CComplex (do
9、uble r, double i) real = r; imag = i; ,第6章 多态性,例6.2 (续一),void CComplex:Print() cout ( real , imag ) endl; CComplex CComplex:operator +(CComplex c) CComplex temp; temp.real = real + c.real; temp.imag = imag + c.imag; return temp; CComplex CComplex:operator -(CComplex c) CComplex temp; temp.real = rea
10、l - c.real; temp.imag = imag - c.imag; return temp; ,第6章 多态性,例6.2 (续二),CComplex CComplex:operator *(CComplex c) CComplex temp; temp.real = real * c.real - imag * c.imag; temp.imag = real * c.imag + imag * c.real; return temp; void main(void) CComplex a(1, 2), b(3.0, 4.0), c, d, e, f; c = a+b; d = a-
11、b; e = a*b; f = a+1; cout c = ; c.Print(); cout d = ; d.Print(); cout e = ; e.Print(); cout f = ; f.Print(); ,第6章 多态性,程序运行结果为: c = (4, 6) d = (-2, -2) e = (-5,10) f = (2, 2),总结:设有双目运算符 B,如果要重载 B 为类的成员函数,使之能够实现表达式 oprd1 B oprd2,其中 oprd1 为A 类对象,则 B 应被重载为 A 类的成员函数,形参类型应该是 oprd2 所属的类型。 经重载后,表达式oprd1 B o
12、prd2 相当于 oprd1.operator B(oprd2),注意重载双目运算符只需要一个参数。,6.2 运算符重载为类的成员函数,6.2.2 单目运算符重载 单目运算符,如果重载为类的成员函数,不需要参数。 为区分前置和后置运算符,C+规定: 对于前置单目运算符,重载函数没有参数 对于后置单目运算符,重载函数有一个整型参数,这个整型参数没有其他用途,只是用于区分前置运算与后置运算。,第6章 多态性,例6.3 定义一个CInt类,类中只有一个数据成员i,两个运算符“+”的重载函数,一个没有参数,实现的是前置运算符重载,另一个有一个整型参数,实现后置运算符重载。,#include iostr
13、eam using namespace std; class CInt private: int i; public: CInt(int a=0); void Print(); CInt operator +(); CInt operator +(int); ; CInt:CInt (int a) i = a; ,第6章 多态性,void CInt:Print() cout i= i endl; CInt CInt:operator +() CInt temp; temp.i = +i; return temp; CInt CInt:operator +(int) CInt temp; tem
14、p.i = i+; return temp; ,例6.3 (续),void main(void) CInt a(5), b(5), c, d; c = a+; d = +b; cout a: ; a.Print(); cout b: ; b.Print(); cout c: ; c.Print(); cout d: ; d.Print(); ,第6章 多态性,程序运行结果为: a: i=6 b: i=6 c: i=5 d: i=6,6.2 运算符重载为类的成员函数,6.2.3 赋值运算符重载 如果类中只包含简单数据类型的数据成员,则使用C+提供的赋值运算符“=”就可以实现将一个对象赋给另一个对
15、象。如前面复数类的对象,就可以将一个对象直接赋给另一个对象。但如果类的数据成员比较复杂(如含有指针),这样直接赋值就会产生问题,我们必须重载赋值运算符“=”才能正确使用“=”。,第6章 多态性,例6.4 类A只有一个数据成员str,是一个字符指针,在构造函数中为str申请存储空间并赋值,在析构函数中释放内存。,#include iostream #include string using namespace std; class A private: char *str; public: A(char *s=no data); A(); void print(); ; A:A (char *s
16、) int len = strlen(s); str = new charlen+1; strcpy(str,s); ,第6章 多态性,例6.4 (续),A:A () if(str) delete str; void A:print() cout str endl; void main(void) A *p = new A(AAAA); A a1; a1=*p; a1.print(); delete p; a1.print(); ,第6章 多态性,例6.5 带有重载赋值运算符的A类,#include iostream #include string using namespace std; c
17、lass A private: char *str; public: A(char *s=no data); A(); A ,第6章 多态性,例6.5 (续一),A:A () if(str) delete str; A ,第6章 多态性,例6.5 (续二),void main(void) A *p = new A(AAAA); A a1; a1=*p; a1.print(); delete p; a1.print(); ,第6章 多态性,程序运行结果为: AAAA AAAA,6.3 运算符重载为类的友元函数,6.3.1 问题的提出 (1)复数与复数相加(c1,c2,c3是复数类的对象)。 c3
18、=c1+c2; (2)一个复数与一个实数的加法运算 c3=c1+10.8; (3)一个实数与一个复数相加就会出现错误。 c3= 10.8 + c1; 因为加号左边的运算对象是实数,C+试图将加号右边的运算对象解释为实数,但C+无法将一个复数转换为一个实数,从而产生错误。 将运算符重载为友元函数可以解决这个问题。,第6章 多态性,6.3 运算符重载为类的友元函数,6.3.2 运算符重载为友元函数 类中的声明: friend 函数类型 operator 运算符(参数表); 运算符重载函数的定义形式: 函数类型 operator 运算符(参数表) 函数体; ,第6章 多态性,例6.6 用友元函数实现
19、复数类加减运算符的重载,#include iostream using namespace std; class CComplex private: double real; double imag; public: CComplex(double r=0, double i=0); void Print(); friend CComplex operator +(CComplex c1,CComplex c2); friend CComplex operator -(CComplex c1,CComplex c2); ; CComplex:CComplex (double r, double
20、 i) real = r; imag = i; ,第6章 多态性,例6.6 (续一),void CComplex:Print() cout ( real , imag ) endl; CComplex operator +(CComplex c1, CComplex c2) CComplex temp; temp.real = c1.real + c2.real; temp.imag = c1.imag + c2.imag; return temp; CComplex operator -(CComplex c1, CComplex c2) CComplex temp; temp.real =
21、 c1.real - c2.real; temp.imag = c1.imag - c2.imag; return temp; ,第6章 多态性,例6.6 (续二),void main(void) CComplex a(1, 2), b(3.0, 4.0), c, d, e; c = a+b; d = b-10; e = 20+a; cout c = ; c.Print(); cout d = ; d.Print(); cout e = ; e.Print(); ,第6章 多态性,相当于函数调用“c=operator+(a, b)”,程序运行结果为: c = (4, 6) d = (-7, 4
22、) e = (21, 2),总结:设有双目运算符 B,如果要重载 B 为类的友元函数,则该友元函数也有两个参数,分别为运算符的两个运算对象。重载后,表达式oprd1 B oprd2 等同于调用函数operator B(oprd1,oprd2 )。 单目运算符也可以重载为类的友元函数,该友元函数有一个参数。,6.4 虚函数,6.4.1 用虚函数实现动态多态 回顾例5.6 void main() CShape *ps3; CShape s(Red); CPoint p1(10,10), p2(100,100),p3(50,50); CLine l(p1,p2,Green); CCircle c(p
23、3, 20, Black); ps0 = ,第6章 多态性,程序运行结果为: Draw a Shape. The color is Red Draw a Shape. The color is Green Draw a Shape. The color is Red Black,为了能通过基类的指针调用派生类的成员函数,可以使用虚函数的方法,即把成员函数Draw()声明为虚函数。,例6.7 用虚函数实现动态多态,#include #include using namespace std; class CPoint private: int X; int Y; public: CPoint(in
24、t x=0, int y=0) X=x; Y=y; CPoint(CPoint ,第6章 多态性,例6.7 (续一),class CShape private: char Color10; public: CShape(char *c) strcpy(Color,c); virtual void Draw() cout Draw a Shape. The color is Color endl; void PrintColor() cout Color endl; ;,第6章 多态性,例6.7 (续二),class CLine:public CShape private: CPoint Sta
25、rt; CPoint End; public: CLine(CPoint s, CPoint e, char *c):CShape(c),Start(s),End(e) virtual void Draw() cout Draw a Line from ( Start.GetX() , Start.GetY(); cout ) to ( End.GetX() , End.GetY() ), with color ; PrintColor(); ;,第6章 多态性,例6.7 (续三),class CCircle:public CShape private: CPoint Center; int
26、Radius; public: CCircle(CPoint ctr, int r, char *c):CShape(c),Center(ctr) Radius = r; virtual void Draw() cout Draw a Circle at center ( Center.GetX() , ; cout Center.GetY() ) with radius Radius and color ; PrintColor(); ;,第6章 多态性,例6.7 (续四),void main() CShape *ps3; CShape s(Red); CPoint p1(10,10), p
27、2(100,100),p3(50,50); CLine l(p1,p2,Green); CCircle c(p3, 20, Black); ps0 = ,第6章 多态性,程序运行结果为: Draw a Shape. The color is Red Draw a Line from (10, 10) to (100, 100) , with color Green Draw a Circle at center (50, 50) with radius 20 and color Black,6.4 虚函数,6.4.1 用虚函数实现动态多态(续) 总结: (1)将成员函数声明为虚函数,在函数原型
28、前加关键字virtual,如果成员函数的定义直接写在类中,也在前面加关键字virtual。 (2)将成员函数声明为虚函数后,再将基类指针指向派生类对象,在程序运行时,就会根据指针指向的具体对象来调用各自的虚函数,称之为动态多态。 (3)如果基类的成员函数是虚函数,在其派生类中,原型相同的函数自动成为虚函数。,第6章 多态性,6.4 虚函数,6.4.2 用虚函数实现动态多态的机制 为了实现动态多态,编译器对每个包含虚函数的类创建一个虚函数地址表,并设置一个虚函数地址指针指向这个对象的虚函数地址表。使用基类指针对虚函数调用时,通过这个虚函数地址指针,在虚函数地址表中查找函数地址。 由于包含虚函数的
29、类,有一个虚函数地址指针,与没有虚函数的类相比,含有虚函数类的对象所占用的存储空间要多一个指针所占用的内存。,第6章 多态性,例6.8 含有虚函数类的对象所占用的存储空间。,#include using namespace std; class A private: int a; public: virtual void func() ; class B : public A private: int b; public: virtual void func() virtual void func1() ; void main(void) cout sizeof(A)= sizeof(A) e
30、ndl; cout sizeof(B)= sizeof(B) endl; ,第6章 多态性,程序运行结果为: sizeof(A)=8 sizeof(B)=12,6.4 虚函数,6.4.2 用虚函数实现动态多态的机制(续) 每个含有虚函数类的对象都有一个虚函数地址指针,指向该类虚函数表,如果用基类的指针调用虚函数,在编译时,并不能确定这个指针的具体指向,而是在运行时,根据指针所指向的具体对象(基类的对象或其派生类的对象),虚函数地址指针才有一个确定的值,即相应类的这个虚函数的地址。从而实现动态多态。,第6章 多态性,6.4 虚函数,6.4.3 虚析构函数 析构函数也可以定义为虚函数,如果基类的析
31、构函数定义为虚析构函数,则派生类的析构函数就会自动成为虚析构函数。 如果基类的指针指向派生类对象,当用delete删除这个对象时,若析构函数不是虚函数,就要调用基类的析构函数,而不会调用派生类的析构函数。如果为基类和派生类的对象分配了动态内存,或者为派生类的对象成员分配了动态内存,这时释放的只是基类中动态分配的内存,而派生类中动态分配的内存未被释放,因此一般应将析构函数定义为虚析构函数。,第6章 多态性,例6.9 定义职员类CEmployee,数据成员有姓名(字符指针型数据)和年龄,由CEmployee类派生出教师类CTeacher,增加数据成员教学简历(字符指针型数据)。,#include
32、#include using namespace std; class CEmployee private: char *name; int age; public: CEmployee(char *n, int a); virtual CEmployee(); ; CEmployee:CEmployee(char *n, int a) name=new charstrlen(n)+ 1 ; strcpy(name, n); age = a; ,第6章 多态性,例6.9 (续一),CEmployee:CEmployee() cout Destruct CEmployee endl; if(na
33、me) delete name; class CTeacher : public CEmployee private: char *mainCourse; public: CTeacher(char *n, char *course, int a); virtual CTeacher(); /由于基类已定义虚析构函数,此处也可不加virtual ; CTeacher:CTeacher(char *n, char * course, int a) : CEmployee(n,a) mainCourse = new charstrlen(course)+1; strcpy(mainCourse,
34、course); ,第6章 多态性,例6.9 (续二),CTeacher:CTeacher() cout Destruct CTeacher endl; if(mainCourse) delete mainCourse; void main(void) CEmployee *p3; p0 = new CEmployee(Name1, 20); p1 = new CTeacher(Name2,C for 2 years,C+ 3 years,26); p2 = new CTeacher(Name3,Data structure for 2 years,C+ 3 years,30); for(in
35、t i=0; i3; i+) delete pi; ,第6章 多态性,程序运行结果为: Destruct CEmployee Destruct CTeacher Destruct CEmployee Destruct CTeacher Destruct CEmployee,若不定义为虚析构函数,程序运行结果为: Destruct CEmployee Destruct CEmployee Destruct CEmployee,由于未调用CTeacher类析构函数,导致成员mainCourse空间未被释放,6.4 虚函数,6.4.4 纯虚函数与抽象类 纯虚函数是不必定义函数体的特殊虚函数,纯虚函数的声明格式为: virtual 函数类型 函数名(参数表)= 0; 含有纯虚函数的类称为抽象类。抽象类常常用作派生类的基类。 如果派生类继承了抽象类的纯虚函数,却没有重新定义原型相同且带函数体的虚函数,或者派生类定义了基类所没有定义的纯虚函数,则派生类仍然是抽象类,在多层派生的过程中,如果到某个派生类为止,所有纯虚函数都已全部重新定义,则该派生类就成为非抽象类。 不能定义抽象类的对象,但
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024年技术转让中介安全合同
- 2024年度技术转让与许可合同
- 2024年新型商混研发与购买协议
- 2024年度防盗门定制与维护服务合同
- 2024年数据传输与网络安全合同
- 2024商铺租赁信息技术服务合同
- 2024年建筑装饰工程预算协议
- 2024年房产代建合同
- 2024年度基因编辑与合成技术授权许可合同
- DB4113T 052-2024 地理标志产品唐栀子
- 大学英语口语课件
- 商业银行派生存款的过程课件
- 广东食品安全管理人员抽查考核题库(含答案)
- 2022年全国高中数学联赛福建赛区预赛模拟试题及参考答案
- 大学生心理辅导专项试题库(含答案)
- 2023届吉林省吉林大学附属中学化学高一第一学期期中复习检测试题含解析
- HAF003《核电厂质量保证安全规定》的理解要点共课件
- 二年级下册语文课件 猫和老鼠的故事 全国通用
- Unit-8-Stonehenge-公开课公开课一等奖省优质课大赛获奖课件
- 慢性淋巴细胞白血病-课件
- 22G101-1与16G101-1的图集差异
评论
0/150
提交评论