第03章 C++面向对象.ppt

上传人(卖家):hwpkd79526 文档编号:6158655 上传时间:2023-06-04 格式:PPT 页数:73 大小:345.50KB
下载 相关 举报
第03章 C++面向对象.ppt_第1页
第1页 / 共73页
第03章 C++面向对象.ppt_第2页
第2页 / 共73页
第03章 C++面向对象.ppt_第3页
第3页 / 共73页
第03章 C++面向对象.ppt_第4页
第4页 / 共73页
第03章 C++面向对象.ppt_第5页
第5页 / 共73页
点击查看更多>>
资源描述

1、第第3章章C+面向对象程序设计面向对象程序设计 3.1 类和对象类和对象 作业作业13.2 继承和派生类继承和派生类 作业作业23.3 多态和虚函数多态和虚函数 3.4 运算符重载运算符重载 作业作业33.5 输入输出流库输入输出流库 作业作业43.1类和对象类和对象 3.1.1类的定义类的定义 定义类的一般格式如下:class private:public:;类中的数据和函数是类的成员数据和函数是类的成员,分别称为数据成员和成员函数数据成员和成员函数。public类成员,是公有的,能被外面的程序访问是公有的,能被外面的程序访问;private类成员,是私有的,只能由类中的函数所使用,而不能被

2、外,只能由类中的函数所使用,而不能被外面的程序所访问。面的程序所访问。是类定义中的实现部分,这部分包含所有在类体中声明的函数的定义。当类的成员函数的函数体在类的外部定义时,必须由作用域运算符作用域运算符“:”:”来通知编译系统该函数所属的类。3.1类和对象类和对象定义类时应注意:定义类时应注意:(1)(1)不允许对所定义的数据成员进行初始化不允许对所定义的数据成员进行初始化,例如类CMeter中,下面的定义是错误的:class CMeter.private:int m_nPos=10;.;(2)(2)在“public:”或“private:”后面定义的所有成员都是公有或私有的,直到下一个“pu

3、blic:”或“private:”出现为止。(3)3)关键字关键字publicpublic和和privateprivate可以在类中出现多次可以在类中出现多次,且前后的顺序没有关系;(4)(4)关键字protected(保护)也可修饰成员的类型,它与private两者基本相似,但在类的继承时有所不同。(5)(5)数据成员的类型可以是整型、浮点型、字符型、数组、指针和引用等,也数据成员的类型可以是整型、浮点型、字符型、数组、指针和引用等,也可以是另一个类的对象。可以是另一个类的对象。(6)(6)尽量将类单独存放在一个文件中或将类的声明放在类的声明放在.h文件文件中而将成员函数将成员函数的实现放在

4、与的实现放在与.h文件同名的文件同名的.cpp文件中文件中。3.1类和对象类和对象3.1.2 对象的定义对象的定义 定义对象,格式:定义的对象既可是一个普通对象,也可是一个数组对象或指针对象。对象的成员就是该对象的类所定义的成员。对象成员有数据成员和成员函数,其表示方式如下:.()前者用来表示数据成员,后者用来表示成员函数。“.”是一个运算符,用来表示对象的成员。指向对象的指针的成员表示如下:-()“-”与“.”运算符的区别是:“-”用来表示指向对象的指针成员,“.”用来表示一般对象成员。前者表示数据成员,后者表示成员函数。下面的两种表示是等价的:-(*).这对于成员函数也适用。另外,引用对象

5、的成员表示与一般对象的成员表示相同。3.1类和对象类和对象3.1.3构造函数和析构函数构造函数和析构函数 构造函数构造函数 为了能给数据成员自动设置某些初始值,就要使用类的特殊成员函数构造函数。构造函数的最大特点是在对象建立时它会被自动执行,用于变量、对象的初始化代码一般放在构造函数中。构造函数必须与相应的类同名,可以带参数,也可以不带参数,可以重载。例如:class CMeterpublic:CMeter(int nPos=10)/构造函数m_nPos=nPos;.构造函数CMeter(int nPos=10)中,nPos被设置了10,构造函数中相应实参没有被指定时,使用此缺省值。由于构造函

6、数的参数只能在定义对象时指定。CMeter oMeter;和CMeter oMeter(10);3.1类和对象类和对象析构函数析构函数 与构造函数相对应的是析构函数。析构函数是另一种特殊的C+成员函数,它只是在类名称前面加上一个“”符号。每一个类只有一个析构函数,没有任何参数,也不返回任何值。例如:class CMeterpublic:.CMeter()/析构函数.析构函数一般在下列两种情况下被自动调用:(1)(1)当对象定义在一个函数体中,函数调用结束后,析构函数被自动调用当对象定义在一个函数体中,函数调用结束后,析构函数被自动调用。(2)(2)new为对象分配动态内存,用为对象分配动态内存

7、,用delete释放对象时,析构函数被自动调用释放对象时,析构函数被自动调用。3.1类和对象类和对象默认构造函数和析构函数默认构造函数和析构函数 类定义时,如果没有定义任何构造函数,编译器自动生成一个不带参数的默认构造函数,格式如下::()按构造函数的规定,默认构造函数名同类名。默认构造函数的这样格式也可由用户定义在类体中。在程序中定义一个对象而没有指明初始化时,则编译器便按默认构造函数来初始化该对象。默认构造函数对对象初始化时,则将对象的所有数据成员都初始化为零或空。如果一个类中没有定义析构函数,编译系统生成一个默认析构函数,格式::()默认析构函数名与该类的类名同名。是一个空函数。3.1类

8、和对象类和对象构造函数的重载构造函数的重载 例例Ex_ConDefaultEx_ConDefault 带默认参数的构造函数。#include class CDatepublic:CDate(int year=2002,int month=7,int day=30)nYear=year;nMonth=month;nDay=day;coutnYear-nMonth-nDayendl;/其他公共成员private:int nYear,nMonth,nDay;void main()CDate day1;CDate day2(2002,8);运行结果为:2002-7-302002-8-303.1类和对象

9、类和对象拷贝构造函数拷贝构造函数 例例Ex_ConCopyEx_ConCopy 拷贝构造函数的使用。#include class CDatepublic:CDate(int year=2002,int month=7,int day=30)cout调用构造函数endl;nYear=year;nMonth=month;nDay=day;coutnYear-nMonth-nDayendl;CDate(const CDate&ymd)/*拷贝构造函数,是一种特殊的构造函数,它由编译器调用来完成一些基于同一类的其他对象的构建及初始化。其唯一的参数(对象的引用)是不可变的(const类型)。此函数经常用

10、在函数调用时用户定义类型的值传递及返回。拷贝构造函数要调用基类的拷贝构造函数和成员函数。如果可以的话,它将用常量方式调用,另外,也可以用非常量方式调用.*/cout调用拷贝构造函数endl;coutymd.nYear-ymd.nMonth-ymd.nDayendl;private:int nYear,nMonth,nDay;void main()CDate day1(2002,8);CDate day2(day1);3.1类和对象类和对象 例例Ex_ConCopyDefaultEx_ConCopyDefault 默认拷贝构造函数的使用。#include class CDatepublic:CD

11、ate(int year=2002,int month=7,int day=30)cout调用构造函数endl;nYear=year;nMonth=month;nDay=day;void output()coutnYear-nMonth-nDayendl;private:int nYear,nMonth,nDay;void main()CDate day1(2002,8);CDate day2(day1);/调用默认的拷贝函数day1.output();day2.output();运行结果为:调用构造函数2002-8-302002-8-30 3.1类和对象类和对象3.1.4对象成员初始化对象成

12、员初始化 在实际应用中往往需要多个类,这时就可能把一个已定义类的对象作为另一个类的成员。为了能对这些对象成员进行初始化,构造函数定义格式::(形参表):对象1(参数表),对象2(参数表),对象n(参数表)对象1、对象2、对象n就是该类使用的其他类的对象,冒号“:”后面的列表称为成员初始化列表。说明:说明:(1)(1)对象成员必须初始化,但不能将对象成员直接在构造函数体内进行初始化。(2)(2)对象成员初始化时,必须有相应的构造函数,且多个对象成员的构造次序不是按初始化成员列表的顺序,而是按各类声明的先后次序进行的。(3)(3)对象成员初始化也可在类的外部进行,但必须与构造函数在一起。(4)(4

13、)事实上,成员初始化列表也可用于类中的普通数据成员的初始化。3.1类和对象类和对象3.1.5静态成员静态成员 静态数据成员静态数据成员 是同一个类中所有对象共享的成员,不是某一对象的成员。用静态数据成员可以节省内存,是所有对象所公有的,对多个对象来说,静态数据成员只存储一处,供所有对象共用。静态数据成员的值对每个对象都是一样,它的值是可以更新的。静态数据成员是静态存储的,具有静态生存期。定义静态数据成员:(1)(1)使用关键词使用关键词staticstatic声明静态数据成员声明静态数据成员。(2)(2)对静态数据成员进行初始化。静态数据成员要分配空间,不能在类声明中对静态数据成员进行初始化。

14、静态数据成员要分配空间,不能在类声明中进行初始化。静态数据成员初始化在类的外部进行,它的格式如下:进行初始化。静态数据成员初始化在类的外部进行,它的格式如下::=静态成员函数静态成员函数 静态成员函数属于类的静态成员,不是对象成员。对静态成员的引用不需要用对象名。在静态成员函数的实现中不能直接引用类中说明的非静态成员不能直接引用类中说明的非静态成员,可以引用可以引用类中说明的静态成员类中说明的静态成员。如果静态成员函数中要引用非静态成员时,可通过对象来引用。公有的静态成员函数既可以有通过相应的对象访问,也可以通过其所属的类名来引用。3.1类和对象类和对象3.1.6友元友元 例例Ex_Frien

15、dFuncEx_FriendFunc 友元函数的使用。#include class CPointpublic:CPoint()m_x=m_y=0;CPoint(unsigned x,unsigned y)m_x=x;m_y=y;void Print()cout Point(m_x ,m_y )endl;friend CPoint Inflate(CPoint&pt,int nOffset);/声明一个友元函数private:unsigned m_x,m_y;CPoint Inflate(CPoint&pt,int nOffset)/友元函数的定义 CPoint ptTemp=pt;ptTemp

16、.m_x+=nOffset;/直接改变私有数据成员m_x和m_y ptTemp.m_y+=nOffset;return ptTemp;void main()CPoint pt(10,20);pt.Print();pt=Inflate(pt,3);/调用友元函数pt.Print();3.1类和对象类和对象3.1.7常类型常类型 常对象常对象 常对象是指对象常量,定义格式:const 定义常对象要进行初始化,该对象不能再被更新,修饰符定义常对象要进行初始化,该对象不能再被更新,修饰符constconst可以放在类名可以放在类名后面,也可以放在类名前面。后面,也可以放在类名前面。常指针和常引用常指针

17、和常引用 常指针也是使用关键字const来修饰的。有三种形式。第一种形式是将第一种形式是将const放在指针变量的类型之前,表示声明一个指向常量的放在指针变量的类型之前,表示声明一个指向常量的指针。指针。此时,在程序中不能通过指针来改变它所指向的数据值,但可以改变指针本身的值。第二种形式是将第二种形式是将const放在指针定义语句的指针名前,表示指针本身是一个放在指针定义语句的指针名前,表示指针本身是一个常量,称为指针常量或常指针。常量,称为指针常量或常指针。因此,不能改变这种指针变量的值,但可以改变指变量所指向的数据值。第三种形式是将第三种形式是将const在上述两个地方都加,表示声明一个指

18、向常量的指针在上述两个地方都加,表示声明一个指向常量的指针常量,指针本身的值不可改变,常量,指针本身的值不可改变,而且它所指向的数据的值也不能通过指针改变。3.1类和对象类和对象 例例Ex_ConstParaEx_ConstPara 常参数的函数传递。#include class COnepublic:void print(const int*p,int n)/使用常参数,指向常量的指针cout*p;for(int i=1;in;i+)cout,*(p+i);coutendl;private:;void main()int array6=1,2,3,4,5,6;COne one;one.pri

19、nt(array,6);3.1类和对象类和对象常成员函数常成员函数 例例Ex_ConstFuncEx_ConstFunc 常成员函数的使用。#include class COnepublic:COne(int a,int b)x=a;y=b;void print();void print()const;/声明常成员函数private:int x,y;void COne:print()coutx,yendl;void COne:print()constcout使用常成员函数:x,yendl;void main()COne one(5,4);one.print();const COne two(2

20、0,52);two.print();3.1类和对象类和对象常成员函数可以理解成是“只读”函数,既不能更改数据成员的值,也不能调用那些引起数据成员值变化的成员函数,只能调用const成员函数。例如:class CDatepublic:CDate(int mn,int dy,int yr);/构造函数int getMonth()const;/常成员函数void setMonth(int mn);/一般成员函数int month;/数据成员;int CDate:getMonth()const return month;/不能修改数据成员的值,只有一个返回值void CDate:setMonth(in

21、t mn)month=mn;/可以使用赋值等语句,修改数据成员的值 3.1类和对象类和对象常数据成员常数据成员 类型修饰符const不仅可以说明成员函数,也可以说明数据成员。类中声明const数据成员时,只能通过成员初始化列表的方式来生成构造函数对数据成员初始化。例如:例例Ex_ConstDataEx_ConstData 常数据成员的使用。#include class COnepublic:COne(int a):x(a),r(x)/常数据成员的初始化 void print();const int&r;/引用类型的常数据成员private:const int x;/常数据成员static co

22、nst int y;/静态常数据成员;const int COne:y=10;/静态数据成员的初始化void COne:print()coutx=x,y=y,r=rendl;void main()COne one(100);one.print();该程序的运行结果为:x=100,y=10,r=100 3.1类和对象类和对象3.1.8 this指针指针 对一个对象调用成员函数时,编译器将对象的地址赋给this指针,再调用成员函数,每次成员函数存取数据成员时,由隐含作用this指针。可以用*this来标识调用该成员函数的对象。例例Ex_ThisEx_This this指针的使用。#include

23、class COnepublic:COne()x=y=0;COne(int a,int b)x=a;y=b;void copy(COne&a);/对象引用作函数参数 void print()coutx,yM这样的表达式中,其中pa是一个指向A类对象的指针。不同存储的对象生存期不同。所谓对象的生存期是指对象从被指对象从被创建开始到被释放为止的时间。创建开始到被释放为止的时间。按生存期的不同对象分为三种:(1)(1)局部对象局部对象:对象被定义时调用构造函数,该对象被创建,当程序退出定义该对象所在的函数体或程序块时,调用析构函数,释放该对象。(2)(2)静态对象静态对象:当程序第一次执行所定义的静

24、态对象时,该对象被创建,当程序结束时,该对象被释放。(3)(3)全局对象全局对象:当程序开始时,调用构造函数创建该对象,当程序结束时调用析构函数释放该对象。局部对象被定义在函数体或程序块内,作用域小,生存期短。静态对象被定义在文件中,作用域比较大,生存期也比较大。全局对象被定义在某个文件中,作用域在包含该文件的整个程序中,作用域是最大的,生存期也是最长的。3.1类和对象类和对象2.对象的生存期对象的生存期作业作业P368370:118偶数题偶数题3.2继承和派生类继承和派生类 3.2.1单继承单继承 公有继承公有继承(public)公有继承的特点是基类的公有成员和保护成员作为派生类的成员时,它

25、们都保持原有的状态,而基类的私有成员仍然是私有的。例如:class CStick:public CMeterintm_nStickNum;/声明一个私有数据成员public:void DispStick();/声明一个公有成员函数;/注意分号不能省略void CStick:DispStick()m_nStickNum=GetPos();/调用基类CMeter的成员函数coutm_nStickNum;从基类CMeter派生的CStick类除具有CMeter所有公有成员和保护成员外,还有自身的私有数据成员m_nStickNum和公有成员函数DispStick()。注意:注意:派生类中或派生类的对象

26、可以使用基类的公有成员(包括保护成员),例如CStick的成员函数DispStick中调用了基类CMeter的GetPos函数,oStick对象调用了基类的StepIt成员函数;但基类或基类的对象却不可以使用派生类的成员。3.2继承和派生类继承和派生类私有继承私有继承(private)私有继承的特点是基类的公有成员和保护成员都作为派生类的私有成员,并且不能被这个派生类的子类所访问。例例Ex_ClassPrivateDerivedEx_ClassPrivateDerived 派生类的私有继承示例。#include class CMeterpublic:CMeter(int nPos=10)m_n

27、Pos=nPos;CMeter()void StepIt()m_nPos+;int GetPos()return m_nPos;protected:void SetPos(int nPos)m_nPos=nPos;private:int m_nPos;3.2继承和派生类继承和派生类class CStick:private CMeter/从CMeter派生,私有继承intm_nStickNum;/声明一个私有数据成员public:void DispStick();/声明一个公有成员函数void SetStick(int nPos)SetPos(nPos);int GetStick()return

28、 GetPos();void CStick:DispStick()m_nStickNum=GetPos();/调用基类CMeter的成员函数coutm_nStickNum;void main()CMeter oMeter(20);CStick oStick;coutCMeter:oMeter.GetPos(),CStick:oStick.GetStick()endl;oMeter.StepIt();coutCMeter:oMeter.GetPos(),CStick:oStick.GetStick()endl;oStick.DispStick();3.2继承和派生类继承和派生类保护继承保护继承(

29、protected)特点是基类的所有公有成员和保护成员都成为派生类的保护成员,并且只能被它的派生类成员函数或友元访问,基类的私有成员仍然是私有的。注意,注意,一定要区分清楚派生类的对象和派生类中的成员函数对基类的访问是不同的。例如,在公有继承时,派生类的对象可以访问基类中的公有成员,派生类的成员函数可以访问基类中的公有成员和保护成员。在私有继承和保护继承时,基类的所有成员不能被派生类的对象访问,而派生类的成员函数可以访问基类中的公有成员和保护成员。3.2继承和派生类继承和派生类3.2.2派生类的构造函数和析构函数派生类的构造函数和析构函数 派生类的构造函数和析构函数被执行时,基类相应的构造函数

30、和析构函数派生类的构造函数和析构函数被执行时,基类相应的构造函数和析构函数也会被执行。也会被执行。注意,派生类对象在建立时,先执行基类的构造函数,然后执行派生类的派生类对象在建立时,先执行基类的构造函数,然后执行派生类的构造函数。但对于析构函数来说,其顺序刚好相反,先执行派生类的析构构造函数。但对于析构函数来说,其顺序刚好相反,先执行派生类的析构函数,而后执行基类的析构函数。函数,而后执行基类的析构函数。需要注意的是,如果在对派生类进行初始化时,需要对其基类设置初值,则可按下列格式进行:(总参表):(参数表1),(参数表2),(参数表n),对象成员1(对象成员参数表1),对象成员2(对象成员参

31、数表2),对象成员n(对象成员参数表n).构造函数总参表后面给出的是需要用参数初始化的基类名、对象成员名及各自对应的参数表,基类名和对象成员名之间的顺序可以是任意的,基类名和对象成员名之间的顺序可以是任意的,且对于使用默认构造函数的基类和对象成员,可以不列出基类名和对象成员名。这里所说的对象成员是指在派生类中新声明的数据成员,它属于另外一个类的对象。对象成员必须在初始化列表中进行初始化。3.2继承和派生类继承和派生类3.2.3多继承多继承 在类的继承中,允许一个派生类继承多个基类,这种多继承的方式可使派生类具有多个基类的特性,大大提高了程序代码的可重用性。多继承下派生类的定义是按下面的格式:c

32、lass :,.;其中的继承方式还是前面的三种:public、private和protected。例如:class A.class B.class C:public A,private B.派生类C的成员包含了基类A中成员和B中成员以及该类本身的成员。允许一个基类有多个派生类以及从一个基类的派生类中再进行多个层次的派生。3.2继承和派生类继承和派生类3.2.4虚基类虚基类 例例Ex_Conflict Ex_Conflict 基类成员调用的二义性。#include class Apublic:int x;A(int a=0)x=a;class B1:public Apublic:int y1;B

33、1(int a=0,int b=0):A(b)y1=a;class B2:public Apublic:int y2;B2(int a=0,int b=0):A(b)y2=a;3.2继承和派生类继承和派生类class C:public B1,public B2public:int z;C(int a,int b,int d,int e,int m):B1(a,b),B2(d,e)z=m;void print()coutx=xendl;/编译出错的地方couty1=y1,y2=y2endl;coutz=zendl;void main()C c1(100,200,300,400,500);c1.p

34、rint();3.2继承和派生类继承和派生类派生类B1和B2都从基类A继承,这时在派生类中就有两个基类A的拷贝。当编译器编译到“cout”x=“xendl;”语句时,因无法确定成员x是从类B1中继承来的,还是从类B2继承来,产生了二义性,从而出现编译错误。解决这个问题的方法之一是使用域作用运算符“:”来消除二义性,例如若将print()函数实现代码变为:void print()coutB1:x=B1:xendl;coutB2:x=B2:xendl;couty1=y1,y2=y2endl;coutz=zendl;重新运行,结果为:B1:x=200B2:x=400y1=100,y2=300z=50

35、0 使用虚基类的目的是在多重派生的过程中,使公有的基类在派生类中只有一个拷贝,从而解决上述这种二义性问题。3.2继承和派生类继承和派生类 例例Ex_VirtualBaseEx_VirtualBase 虚基类的使用。#include class Apublic:int x;A(int a=0)x=a;class B1:virtualvirtual public Apublic:int y1;B1(int a=0,int b=0):A(b)y1=a;void print(void)coutB1:x=x,y1=y1endl;class B2:virtualvirtual public Apublic

36、:int y2;B2(int a=0,int b=0):A(b)y2=a;void print(void)coutB2:x=x,y2=y2endl;3.2继承和派生类继承和派生类class C:public B1,public B2public:int z;C(int a,int b,int d,int e,int m):B1(a,b),B2(d,e)z=m;void print()B1:print();B2:print();coutz=zendl;void main()C c1(100,200,300,400,500);c1.print();c1.x=400;c1.print()运行结果为:

37、B1:x=0,y1=100B2:x=0,y2=300z=500B1:x=400,y1=100B2:x=400,y2=300z=500 3.2继承和派生类继承和派生类从程序中可以看出:(1)(1)声明一个虚基类的格式如下:virtual 声明虚基类与声明派生类一道进行,写在派生类名的后面。(2)(2)在派生类B1和B2中只有基类A的一个拷贝,改变成员x的值时,由基类B1和B2中的成员函数输出的成员x的值是相同的。(3)(3)由虚基类经过一次或多次派生出来的派生类,在其每一个派生类的构造函数的成员初始化列表中必须给出对虚基类的构造函数的调用,如果未列出,则调用虚基类的默认构造函数,在这种情况下,虚

38、基类的定义中必须要有默认的构造函数。(4)(4)程序中,类C的构造函数尽管分别调用了其基类B1和B2的构造函数,由于虚基类A在类C中只有一个拷贝,所以编译器无法确定应该由类B1的构造函数还是由类B2的构造函数来调用基类A的构造函数。在这种情况下,在执行类B1和B2的构造函数都不调用虚基类A的构造函数,而是在类C的构造函数中直接调用虚基类A的默认构造函数。若将A的构造函数改为:A(int a=100)x=a;则成员x的初始值为100。当然,不能变成:A(int a)x=a;因为类A中没有声明默认构造函数,因此会出现编译错误。可以是:A(int a)x=a;A():x(0)作业作业P370372:

39、1927偶数题偶数题P397:实验实验53.3多态和虚函数多态和虚函数 3.3.1虚函数虚函数 例例Ex_VirtualFuncEx_VirtualFunc 虚函数的使用。#include class CShapepublic:virtual float area()/将area定义成虚函数return 0.0;class CTriangle:public CShapepublic:CTriangle(float h,float w)H=h;W=w;float area()return(float)(H*W*0.5);private:float H,W;3.3多态和虚函数多态和虚函数class

40、 CCircle:public CShapepublic:CCircle(float r)R=r;float area()return(float)(3.14159265*R*R);private:float R;void main()CShape*s2;s0=new CTriangle(3,4);coutarea()endl;s1=new CCircle(5);coutarea()endl;运行结果为:678.5398 3.3多态和虚函数多态和虚函数说明:说明:(1)(1)虚函数在重新定义时参数的个数和类型必须和基类中的虚函数完全匹配。(2)(2)虚函数所具备的上述功能,只有通过基类指针才可

41、得到。虚函数在用对象名和成员运算符以正常方式调用时,不能达到其功能。例如:CShape ss;ss.area();将得到0.0。(3)(3)如果不使用new来创建相应的派生类对象,也可使用下列方法来实现:void main()CShape*p1,*p2;CTriangle tri(3,4);CCircle cir(5);p1=&tri;p2=○coutarea()endl;coutarea()endl;(4)(4)虚函数必须是类的一个成员函数,不能是友元函数,也不能是静态的成员函数。(5)(5)可把析函数定义为虚函数,但不能将构造函数定义为虚函数。通常在释放基类中和其派生类中的动态申请

42、的存储空间时,也要把析构函数定义为虚函数,以便实现撤消对象时的多态性。3.3多态和虚函数多态和虚函数3.3.2纯虚函数和抽象类纯虚函数和抽象类 定义一个基类时,有时会遇到情况:无法定义基类中虚函数的具体实现,其实现完全依赖于其不同的派生类。例如,一个“形状类”由于没有确定的具体形状,因此其计算面积的函数也就无法实现。这时可将基类中的虚函数声明为纯虚函数。声明纯虚函数的一般格式为:声明纯虚函数的一般格式为:virtual virtual()=0)=0;与一般虚函数不同的是:在纯虚函数的形参表后面多了个与一般虚函数不同的是:在纯虚函数的形参表后面多了个“=0=0”。把函数名。把函数名赋于赋于0 0

43、,本质上是将指向函数的指针的初值赋为,本质上是将指向函数的指针的初值赋为0 0。虚函数不能有具体的实现。虚函数不能有具体的实现代码。代码。抽象类是指至少包含一个纯虚函数的特殊的类。它本身不能被实例化,也就抽象类是指至少包含一个纯虚函数的特殊的类。它本身不能被实例化,也就是说不能声明一个抽象类的对象。必须通过继承得到派生类后,在派生类中是说不能声明一个抽象类的对象。必须通过继承得到派生类后,在派生类中定义了纯虚函数的具体实现代码,才能获得一个派生类的对象。定义了纯虚函数的具体实现代码,才能获得一个派生类的对象。例例Ex_VirtualFuncEx_VirtualFunc 虚函数的使用。#incl

44、ude class CShapepublic:virtual float area()=0;/将area定义成纯虚函数;3.3多态和虚函数多态和虚函数class CTriangle:public CShapepublic:CTriangle(float h,float w)H=h;W=w;float area()/在派生类定义纯虚函数的具体实现代码return(float)(H*W*0.5);private:float H,W;class CCircle:public CShapepublic:CCircle(float r)R=r;float area()/在派生类定义纯虚函数的具体实现代码

45、return(float)(3.14159265*R*R);private:float R;3.3多态和虚函数多态和虚函数void main()CShape*pShape;CTriangle tri(3,4);couttri.area()endl;pShape=&tri;coutarea()endl;CCircle cir(5);coutcir.area()endl;pShape=○coutarea()endl;运行结果为:6678.539878.5398 3.4运算符重载运算符重载 3.4.1运算符重载的语法运算符重载的语法 为了重载运算符,必须定义一个特殊的函数,以便通知编译器,遇

46、到该重载运算符时调用该函数,并由该函数来完成该运算符应该完成的操作。这种函数称为运算符重载这种函数称为运算符重载函数函数,通常是类的成员函数或是友元函数,运算符的操作数通常也是该类的对象。定义一个运算符重载函数函数名必须以operator开头,一般形式如下::operator()/函数体重载的运算符必须是一个合法的运算符,如“+”、“-”、“*”、“/”、“+”等。例例Ex_Complex Ex_Complex 运算符的简单重载。#include class CComplexpublic:CComplex(double r=0,double i=0)realPart=r;imagePart=i

47、;void print()cout该复数实部=realPart,虚部=imagePartendl;CComplex operator+(CComplex&c);/重载运算符+CComplex operator+(double r);/重载运算符+private:double realPart;/复数的实部double imagePart;3.4运算符重载运算符重载CComplex CComplex:operator+(CComplex&c)/参数是CComplex引用对象CComplex temp;temp.realPart=realPart+c.realPart;temp.imagePart

48、=imagePart+c.imagePart;return temp;CComplex CComplex:operator+(double r)/参数是double类型数据CComplex temp;temp.realPart=realPart+r;temp.imagePart=imagePart;return temp;void main()CComplex c1(12,20),c2(50,70),c;c=c1+c2;c.print();c=c1+20;c.print();运行结果为:该复数实部=62,虚部=90该复数实部=32,虚部=20 3.4运算符重载运算符重载还需要说明的是:(1)(

49、1)当用成员函数实现双目运算符的重载时,运算符的左操作数一定是对象运算符的左操作数一定是对象,右操作数作为调用运算符重载函数的参数,参数可以是对象、对象的引用右操作数作为调用运算符重载函数的参数,参数可以是对象、对象的引用或是其他类型的参数。或是其他类型的参数。例如,若有表达式“c=20+c1”,则编译器必将“20+c1”解释为“20.operator+(c1)”,显然出现编译错误。但实际应用时,这种运算操作是存在的,解决这个问题的办法是将运算符重载为友元函数(在后面讨论)。(2)(2)不是所有的运算符都可以重载不是所有的运算符都可以重载。在C+中不允许重载的运算符除三目运算符“?:”外,还有

50、成员操作符“.”、成员指针操作符“*”、作用域操作符“:”以及sizeof运算符。(3)(3)只能对只能对C+C+中已定义了的运算符进行重载中已定义了的运算符进行重载,而且当重载一个运算符时,该运算符的操作数个数、优先级和结合性是不能改变的。3.4运算符重载运算符重载3.4.2友元重载友元重载 实现运算符重载的方法有两种:用类的成员函数来实现和通过类的友元函用类的成员函数来实现和通过类的友元函数来实现数来实现。这里来用友元函数实现重载的方法。友元重载方法既可用于单目运算符,也可以用于双目运算符。它们的一般格式如下:friend operator()/单目运算符重载 /函数体friend ope

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 办公、行业 > 各类PPT课件(模板)
版权提示 | 免责声明

1,本文(第03章 C++面向对象.ppt)为本站会员(hwpkd79526)主动上传,163文库仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。
2,用户下载本文档,所消耗的文币(积分)将全额增加到上传者的账号。
3, 若此文所含内容侵犯了您的版权或隐私,请立即通知163文库(发送邮件至3464097650@qq.com或直接QQ联系客服),我们立即给予删除!


侵权处理QQ:3464097650--上传资料QQ:3464097650

【声明】本站为“文档C2C交易模式”,即用户上传的文档直接卖给(下载)用户,本站只是网络空间服务平台,本站所有原创文档下载所得归上传人所有,如您发现上传作品侵犯了您的版权,请立刻联系我们并提供证据,我们将在3个工作日内予以改正。


163文库-Www.163Wenku.Com |网站地图|