第四章类与对象.ppt_第1页
第四章类与对象.ppt_第2页
第四章类与对象.ppt_第3页
第四章类与对象.ppt_第4页
第四章类与对象.ppt_第5页
已阅读5页,还剩35页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、0页,定义类,类是具有相同属性和行为的一组对象的集合,它为属于该类的全部对象提供了统一的抽象描述,其内部包括属性和行为两个主要部分。 利用类可以实现数据的封装、隐藏、继承与派生。 利用类易于编写大型复杂程序,其模块化程度比C中采用函数更高。,类的声明形式,1页,公有类型成员,关键字public声明,它们是类与外部的接口,任何外部函数都可以访问公有类型数据和函数。 公有成员可以被程序中的其他函数(包括main)访问。是对外的窗口。 它们是类的接口,通过接口为外部提供类操作的方法。,私有类型成员,在关键字private后面声明,只允许本类中的函数访问,而类外部的任何函数都不能访问。 关键字缺省:默

2、认private。 class Clock int Hour, Minute, Second; ; private:私有成员只能被该类的成员函数访问。,2页,保护类型,与private类似,其差别表现在继承与派生时对派生类的影响不同,第七章讲。 保护成员可以被该类的派生类的成员函数访问。 但对其它类是隐蔽的,不可访问的。,类的成员,class Clock public: void SetTime(int NewH, int NewM,int NewS); void ShowTime(); private: int Hour, Minute, Second; ; int main() Clock

3、 c1; c1.SetTime(1,1,1); c1.Hour=5;c1.Minute=5; c1.ShowTime(); ,私有成员,不能被外部操作,3页,类的成员,void Clock:SetTime(int NewH, int NewM, int NewS) Hour=NewH; Minute=NewM; Second=NewS; void Clock:ShowTime() coutHour:Minute:Second; ,私有成员,可以被自身成员函数访问,成员数据,与一般的变量声明相同,但需要将它放在类的声明体中。 在类定义时不能给成员数据赋初始值。 class Clock publi

4、c: private: int Hour=2, Minute=3, Second=0; ;,4页,成员函数,在类中说明原型,可以在类外给出函数体实现,并在函数名前使用类名加以限定。也可以直接在类中给出函数体,形成内联成员函数。 允许声明重载函数和带默认形参值的函数,内联成员函数,为了提高运行时的效率,对于较简单的函数可以声明为内联形式。 内联函数体中不要有复杂结构(如循环语句和switch语句)。 在编译时直接嵌入到代码相应位置中。不存在函数调用。 在类中声明内联成员函数的方式: 将函数体放在类的声明中。 使用inline关键字。,5页,内联成员函数举例(一),class Point publ

5、ic: void Init(int initX,int initY) X=initX; Y=initY; int GetX() return X; int GetY() return Y; private: int X,Y; ;,内联成员函数举例(二),class Point public: void Init(int initX,int initY); int GetX(); int GetY(); private: int X,Y; ;,inline void Point: Init(int initX,int initY) X=initX; Y=initY; inline int Poi

6、nt:GetX() return X; inline int Point:GetY() return Y; ,6页,使用类的对象,类的对象是该类的某一特定实体,即类类型的变量。 声明形式: 类名 对象名; 例: Clock myClock; Point A,B; Point *p=,类和对象之间的关系,可以用整型int和整型变量i之间的关系来类比。 C+把类的变量称为类的对象,对象是类的实例化如同i是int的变量。 声明了一个类便声明了一个新的类型,类本身不接受和存储具体的值, 只作为生成具体对象的一种“样板”, 定义了对象后,系统才为对象分配存储空间。 如果在函数外,在声明类的同时定义的对象

7、是一个全局的对象。如: class point op1,op2; main() ,对象,7页,类中成员的访问方式,类中成员互访 直接使用成员名 类外访问 使用“对象名.成员名”方式访问 public 属性的成员 使用“对象指针-成员名”方式访问 public 属性的成员,例4-1类的应用举例,#include using namespace std; class Clock ./类的声明略 . /类的实现略 int main() Clock myClock; myClock.SetTime(8,30,30); myClock.ShowTime(); ,8页,构造函数,构造函数的作用是在对象被创

8、建时使用特定的值构造对象,或者说将对象初始化为一个特定的状态。 在对象创建时由系统自动调用。 如果程序中未声明,则系统自动产生出一个默认形式的构造函数 允许为内联函数、重载函数、带默认形参值的函数 类的构造与析构分别由类的构造函数和析构函数来实现,其中构造函数与析构函数与类同名,只是析构函数前多了一个 符号。,构造函数和析构函数具有普通成员函数的许多共同特性,但还具有一些独特的特性,我们可以把它们归纳成下面几点: 它们都没有返回值说明,也就是说定义构造函数和析构函数时不需指出类型。 它们不能被继承。 和大多数C+函数一样,构造函数可以有缺省参数。 析构函数可以是虚的(visual),但构造函数

9、不行。 不可取它们的地址。 不能用常规调用方法调用构造函数;当使用完全的限定名(带对象名、类名和函数名)时可以调用析构函数。 当定义对象时,程序自动调用构造函数;当删除对象时,程序自动调用析构函数。,9页,构造函数举例,class Clock public: Clock(int NewH,int NewM,int NewS);/构造函数 void SetTime(int NewH,int NewM,int NewS); void ShowTime(); private: int Hour,Minute,Second; ;,与类同名,构造函数的实现: Clock:Clock(int NewH,

10、int NewM, int NewS) Hour= NewH; Minute= NewM; Second= NewS; 建立对象时构造函数的作用: int main() Clock c(0,0,0); /隐含调用构造函数,将初始值作为实参。 c.ShowTime(); ,在类外实现,需要域作用符,10页,缺省的构造函数,如果用户不定义构造函数和析构函数,则系统自动生成类的构造函数和析构函数,只是这时只能分配和释放对象实例的存储空间,而不进行初始化、指针空间处理或其他工作。 class point private: int x,y; public: setpoint(int,int); ; ma

11、in() point p1,p2; /定义类point的对象x1,x2时调用构造函数 . . p1=p2; /什麽时候析构 ,无自定义构造函数,11页,class complex private: double real; double imag; public: complex(double r=0.0,double i=0.0); double abscomplex(); 这时: complex s1; /全部用缺省值 complex s2(1.1); /只传递一个参数 complex s3(1.1,2.2); /传递二个参数,构造函数参数的缺省值,在上面定义了三个对象sl,s2,s3,它

12、们都是定义合法的对象,传递不同的参数,使它们的私有成员real,imag取得不同的值。 对象s1,因为在定义时没有传递参数,所以real,imag均取构造函数的缺省参数值为其赋值,因此real,imag均为0值。 对象s2,在定义时只传递了一个参数,传递的这个参数就给了构造函数中的第一个参量,而第二个参量取缺省值,所以对象s2的私有成员real取值为1.1,而y为0。 对象s3,在定义时传递了两个参数,这两个参数分别给了私有成员real和imag取值为1.1,y为2.2。,12页,构造函数参数的缺省值,缺省参数并不只用于构造函数,一般的成员函数,甚至于一般的全局函数都可以使用缺省参数。 在许多

13、应用中,经常会遇到这样的情况,在函数所带的参数中,有一部分可以缺省,而有一部分不可缺省。此时所采取的规则是,所有取缺省值的参数必须出现在不取缺省值的参数的右边。也就是说所有的缺省参数必须是参数表中最后的参数。下面的例子非常清楚地描述了这个原则:,13页,构造函数的二义性问题,在定义构造函数时,一定要注意,所定义的多个构造函数之间,在参数的个数或类型上必须存在差异,否则在系统调用时就会出现二义性。 我们在上一节讲了函数的缺省参数,在定义多个构造函数,又使用缺省参数时,特别要注意防止出现二义性。,下面我们用一个main()函数来使用这个类: main() / X one(10); /定义x类的两个

14、对象 X two; / 上面定义了两个对象: 对象one,在定义过程中,传递了一个整型参量10,它与x(int)相匹配,因此在创建对象one的同时,调用构造函数x(inti20)对对象one初始化。 对象two,在定义过程中,没有传递参数,此时有两种可能的情况:第一种是在创建对象时调用不带参数的构造函数x()来对对象初始化;另一种情况是在创建对象时调用带缺省参数的构造函数x(int I=0)来对对象进行初始化,参数取缺省值0。这两种情况的存在使系统无法确定到底调用哪个构造函数,这就出现了二义性。,14页,复制构造函数,复制构造函数是一种特殊的构造函数,其形参为本类的对象引用。 class 类名

15、 public : 类名(形参);/构造函数 类名(类名 Y=yy; Point(Point,Point:Point (Point ,15页,复制构造函数(例4-2),当用类的一个对象去初始化该类的另一个对象时,系统自动调用复制构造函数实现拷贝赋值。 int main() Point A(1,2); Point B(A); /复制构造函数被调用,显式 Point C=A; /复制构造函数被调用,复制式 coutB.GetX()endl; ,若函数的形参为类对象,调用函数时,实参赋值给形参,系统自动调用复制构造函数。例如: void fun1(Point p) coutp.GetX()endl;

16、 int main() Point A(1,2); fun1(A); /调用复制构造函数 ,16页,复制构造函数(例4-2),当函数的返回值是类对象时,系统自动调用复制构造函数。例如: Point fun2() Point A(1,2); return A; /调用复制构造函数 int main() Point B; B=fun2(); ,17页,默认的复制构造函数,如果程序员没有为类声明复制初始化构造函数,则编译器自己生成一个默认的复制构造函数。 这个构造函数执行的功能是:用作为初始值的对象的每个数据成员的值,初始化将要建立的对象的对应数据成员。,缺省复制构造函数的功能: class poi

17、nt int x, y; public: point(int a, int b) x=a;y=b; void print() coutx yendl; void setx(int i) x=i; ; int main( ) point p1(30,40); point p2(p1); point p3=p1; p3.setx(9); p1.print(); p2.print(); p3.print(); return 0; ,p2.x=p1.x; p2.y=p1.y; 为什么要自定义?,18页,4.3 析构函数,完成对象被删除前的一些清理工作。 在对象的生存期结束的时刻系统自动调用它,然后再释

18、放此对象所属的空间。 如果程序中未声明析构函数,编译器将自动产生一个默认的析构函数。,19页,构造函数和析构函数举例,#include using namespace std; class Point public: Point(int xx,int yy); Point(); /.其他函数原型 private: int X,int Y; ; Point:Point(int xx, int yy) X=xx; Y=yy; Point:Point() /.其他函数的实现略 类的析构函数不接受参数也不返回数值,类只有一个析构函数,不能进行析构函数的重载。,20页,构造和析构的顺序,class Cr

19、eateAndDestroy public: CreateAndDestroy( int, string ); / constructor CreateAndDestroy(); / destructor private: int data; string memo; zero(0, zero ); CreateAndDestroy : CreateAndDestroy( int value, string str) data = value; memo=str; cout Object memo constructorendl; CreateAndDestroy : CreateAndDes

20、troy() cout Object memo destructor endl; ,21页,构造和析构的顺序,void create( void ); / prototype CreateAndDestroy first( 1, first ); / global object int main() cout (global created before main) endl; CreateAndDestroy second( 2, second ); / local object cout (local automatic in main) endl; static CreateAndDes

21、troy third( 3, third ); / local object cout (local static in main) endl; create(); / call function to create objects CreateAndDestroy fourth( 4, fourth ); / local object cout (local automatic in main) endl; ,22页,构造和析构的顺序,/ Function to create objects void create( void ) CreateAndDestroy fifth( 5, fif

22、th ); cout (local automatic in create) endl; static CreateAndDestroy sixth( 6, sixth ); cout (local static in create) endl; CreateAndDestroy seventh( 7, seventh ); cout (local automatic in create) endl; ,23页,构造和析构的顺序,24页,4.4 调用复制构造函数的综合实例,一圆形游泳池如图所示,现在需在其周围建一圆形过道,并在其四周围上栅栏。栅栏价格为35元/米,过道造价为20元/平方米。过道

23、宽度为3米,游泳池半径由键盘输入。要求编程计算并输出过道和栅栏的造价。,#include using namespace std; const float PI = 3.14159; const float FencePrice = 35; const float ConcretePrice = 20; /声明类Circle 及其数据和方法 class Circle private: float radius; public: Circle(float r); /构造函数 float Circumference() const; /圆周长 float Area() const; /圆面积 ;,

24、/ 类的实现 / 构造函数初始化数据成员radius Circle:Circle(float r) radius=r / 计算圆的周长 float Circle:Circumference() const return 2 * PI * radius; / 计算圆的面积 float Circle:Area() const return PI * radius * radius; int main () float radius; float FenceCost, ConcreteCost; / 提示用户输入半径 coutradius; / 声明 Circle 对象 Circle Pool(ra

25、dius); Circle PoolRim(radius + 3);,25,/计算栅栏造价并输出 FenceCost=PoolRim.Circumference()*FencePrice; coutFencing Cost is ¥FenceCostendl; /计算过道造价并输出 ConcreteCost=(PoolRim.Area()- Pool.Area()*ConcretePrice; coutConcrete Cost is ¥ConcreteCostendl; 运行结果 Enter the radius of the pool: 10 Fencing Cost is ¥2858.8

26、5 Concrete Cost is ¥4335.39,26,能不能用一个成员函数来代替?,27页,组合的概念:类成员对象,类中的成员数据是另一个类的对象。 可以在已有抽象的基础上实现更复杂的抽象。,举例,class Point private: float x,y; /点的坐标 public: Point(float h,float v); /构造函数 float GetX(void); /取X坐标 float GetY(void); /取Y坐标 void Draw(void); /在(x,y)处画点 ; /.函数的实现略,class Line private: Point p1,p2; /

27、线段的两个端点 public: Line(Point a,Point b); /构造函数 void Draw(void); /画出线段 ; /.函数的实现略,组合类成员对象,调用了什么?,28页,类组合的构造函数设计,原则:不仅要负责对本类中的基本类型成员数据赋初值,也要负责对象成员初始化。 声明形式: 类名:类名(对象成员所需的形参,本类成员形参) :对象成员1(参数),对象成员2(参数),. 本类初始化 ,类组合的构造函数调用,构造函数调用顺序:先调用内嵌对象的构造函数(按内嵌时的声明顺序,先声明者先构造)。然后调用本类的构造函数。(析构函数的调用顺序相反) 若调用默认构造函数,则内嵌对象

28、的初始化也将调用相应的默认构造函数。,29页,类的组合举例(二),class Part /部件类 public: Part(); Part(int i); Part(); void Print(); private: int val; ;,class Whole public: Whole(); Whole(int i,int j,int k); Whole(); void Print(); private: Part one; Part two; int date; ;,Whole:Whole() date=0; Whole:Whole(int i,int j,int k): two(i),

29、one(j),date(k) Whole自身的处理 /.其他函数的实现略,30,class Employee public: Employee(.); Employee(); void print(); private: char firstName100; char lastName100; /下面两行应该写什么? ? ? Employee:Employee(char *fname,char *lname, int bmonth,int bday,int byear, int hmonth,int hday,int hyear) :birthDate(bmonth,bday,byear),h

30、ireDate(hmonth,hday,hyear) ? ,class Date int year; int month; int day; public: Date(int,int,int); ;,31页,前向引用声明,类应该先声明,后使用 如果需要在某个类的声明之前,引用该类,则应进行前向引用声明。 前向引用声明只为程序引入一个标识符,但具体声明在其他地方。,前向引用声明举例,class B; /前向引用声明 class A public: void f(B b); ; class B public: void g(A a); ;,因为这里要用,32页,前向引用声明注意事项,使用前向引用声

31、明虽然可以解决一些问题,但它并不是万能的。需要注意的是,尽管使用了前向引用声明,但是在提供一个完整的类声明之前,不能声明该类的对象,也不能在内联成员函数中使用该类的对象。请看下面的程序段: class Fred; /前向引用声明 class Barney Fred x; /错误:类Fred的声明尚不完善 ; class Fred Barney y; ;,33页,前向引用声明注意事项,class Fred;/前向引用声明 class Barney public: void method() x-yabbaDabbaDo();/错误:Fred类的对象在定义之前被使用 private: Fred* x;/正确,经过前向引用声明,可以声明Fred类的

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论