谭浩强C程序设计第四版_第1页
谭浩强C程序设计第四版_第2页
谭浩强C程序设计第四版_第3页
谭浩强C程序设计第四版_第4页
谭浩强C程序设计第四版_第5页
已阅读5页,还剩99页未读 继续免费阅读

下载本文档

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

文档简介

第7章类与对象C++语言程序设计教程第7章类与对象1整理ppt第7章类与对象1.掌握类的定义,会根据需求设计类;2.会根据类创建各种对象;3.掌握对象的各种成员的使用方法;4.会设计构造函数与拷贝构造函数来初始化对象;理解其调用过程与顺序;5.理解浅拷贝与深拷贝的概念;6.掌握动态对象以及动态对象数组的建立与释放。7.理解类的静态成员的概念;8.理解友元函数与友元类的概念;9.掌握常对象与常成员的使用;10.了解对象在内存中的分布情况。学习目标

C++语言程序设计教程第7章类与对象2整理ppt7.1类与对象

在面向过程的结构化程序设计中,程序模块是由函数构成,函数将对数据处理的语句放在函数体内,完成特定的功能,数据则通过函数参数传递进入函数体。在面向对象的程序设计中,程序模块是由类构成的。类是对逻辑上相关的函数与数据的封装,它是对问题的抽象描述。面向对象的程序设计方法就是运用面向对象的观点来对现实世界中的各种问题进行抽象,然后用计算机程序来描述并解决该问题,这种描述和处理是通过类与对象实现的。

类与对象是C++程序设计中最重要的概念

C++语言程序设计教程第7章类与对象3整理ppt

每一个实体都是对象,每个对象都属于一个特定的类型。在C++中对象的类型称为类(class)。类代表了某一批对象的共性和特征。类是对象的抽象,而对象是类的具体实例(instance)。正如同结构体类型和结构体变量的关系一样,人们先声明一个结构体类型,然后用它去定义结构体变量。同一个结构体类型可以定义出多个不同的结构体变量。4整理ppt结构体类型:

structStudent{intnum;charname[20];charsex;};Studentstud1,stud2;类:classStudent{intnum;charname[20];charsex;voiddisplay(){cout<<″num:″<<num<<endl;cout<<″name:″<<name<<endl;cout<<″sex:″<<sex<<endl;}};Studentstud1,stud25整理ppt【例7-1】模拟时钟

分析:不管什么样的时钟,也不管各种时钟是如何运行的,它都具有时、分、秒3个属性。除了运行、显示时间的基本功能外,还有设置(调整)时间、设置闹钟等功能。将时钟的这些属性与功能抽象出来,分别给出面向过程的程序与面向对象的程序来实现对时钟的模拟。

思考:二者有何不同?C++语言程序设计教程第7章类与对象6整理ppt******************************p7_1_b.cpp**面向对象的时钟程序*******************************/#include<iostream>usingnamespacestd;classClock{private:intH,M,S;public:

voidSetTime(inth,intm,ints){H=(h>=0&&h<24)?h:0;M=(m>=0&&m<60)?m:0;S=(s>=0&&s<60)?s:0;}

voidShowTime(){cout<<H<<":"<<M<<":"<<S<<endl;}};voidmain(void){ClockMyClock;MyClock.ShowTime();MyClock.SetTime(8,30,30);MyClock.ShowTime();}/******************************p7_1_a.cpp**面向过程的时钟程序*******************************/#include<iostream>usingnamespacestd;structClock{intH,M,S;};ClockMyClock;voidSetTime(intH,intM,intS){MyClock.H=(H>=0&&H<24)?H:0;MyClock.M=(M>=0&&M<60)?M:0;MyClock.S=(S>=0&&S<60)?S:0;}voidShowTime(){cout<<MyClock.H<<":";cout<<MyClock.M<<":";cout<<MyClock.S<<endl;}voidmain(void){ShowTime(); SetTime(8,30,30);ShowTime();}123456789101112131415161718192021222324252627时钟程序B时钟程序A运行结果:0:0:0-85893460:-85893460:-58934608:30:308:30:30

程序解释:通过对上述两种方案的程序进行简单的观察,可以发现它们存在下面几点不同:在程序A中,时钟数据用一个结构型的变量存储,对时钟数据的存取通过函数实现。由于存储时钟数据的是一个全局变量,在任何地方都可见,可以不通过函数单独存取时钟数据。程序B中,只能通过类提供的函数操作时钟。程序A中,数据与对数据操作相互独立,数据作为参数传递给函数。程序B中,数据与对数据的操作构成一个整体。程序A与程序B运行的初始结果不同。这是因为在程序A中,变量是全局的;在程序B中,对象(变量)MyClock是函数main()中的局部对象。全局变量与局部变量在没有初始化时,取初值方式不同,这样造成了运行结果不同。将第23行移出main()外,使之变成全局对象后,两程序结果完全相同。在程序B中发现,一个以class开头的类似结构体的结构,将时钟的数据与对数据进行处理的函数包括在一起,这就是用C++实现的类。C++语言程序设计教程第7章类与对象7整理ppt7.1.2类的定义

class类名

{

public:

公有数据成员或公有函数成员的定义;

protected:

保护数据成员或保护函数成员的定义;

private:

私有数据成员或私有函数成员的定义;};说明:

关键字class表明定义的是一个类;类名是类的名称,应是一个合法的标识符;

public、protected、private为存取控制属性(访问权限),用来控制对类的成员的存取。如果前面没有标明访问权限,默认访问权限为private。类的成员有数据成员与函数成员两类,类的数据成员和函数成员统称为类的成员,类的数据成员一般用来描述该类对象的属性,称为属性;函数成员是描述类行为,称作方法。函数成员由函数构成,这些作为类成员的函数因此也叫成员函数。

简单讲,类是一个包含函数的结构体。因此,类的定义与结构类型的定义相似,其格式如下:

C++语言程序设计教程第7章类与对象8整理ppt7.1.2类的定义

例如:例7-1中定义了一个时钟类Clock。C++语言程序设计教程第7章类与对象9整理ppt

在C++中也是先声明一个类类型,然后用它去定义若干个同类型的对象。对象就是类类型的一个变量。可以说类是对象的模板,是用来定义对象的一种抽象类型。类是抽象的,不占用内存,而对象是具体的,占用存储空间。在一开始时弄清对象和类的关系是十分重要的。类是用户自己指定的类型。如果程序中要用到类类型,必须自己根据需要进行声明,或者使用别人已设计好的类。C++标准本身并不提供现成的类的名称、结构和内容。在C++中声明一个类类型和声明一个结构体类型是相似的。10整理ppt1.数据成员

类定义中的数据成员描述了类对象所包含的数据类型,数据成员的类型可以是C++基本数据类型,也可以是构造数据类型。structRecord{ charname[20];intscore;};classTeam{private:intnum;//基本数据类型

Record*p;//构造数据类型};C++语言程序设计教程第7章类与对象11整理pptclassTeam;//已定义的类classGrade{ Teama;//使用了已定义的类类型

Grade*p;//使用正在定义的类类型定义指针成员

Grade&r;//使用正在定义的类类型定义引用成员

Gradeb;//错误!

使用了未定义完的类Record定义变量};注意:

因为类只是一种类型,类中的数据成员不占内存空间,因此在定义数据成员时不能给数据成员赋初值。类的数据成员除了可以使用前面讲述的C++类型外,还可以使用已定义完整的类类型。在正在定义的类中,由于该类型没有定义完整,所以不能定义该类类型的变量,只能定义该类类型的指针成员以及该类类型的引用成员。C++语言程序设计教程第7章类与对象12整理ppt2.成员函数

作为类成员的成员函数描述了对类中的数据成员实施的操作。成员函数的定义、声明格式与非成员函数(全局函数)的格式相同。成员函数可以放在类中定义,也可以放在类外。放在类中定义的成员函数为内联(inline)函数。

Clock类中的成员函数就是放在类内定义的。

C++可以在类内声明成员函数的原型,在类外定义函数体。这样做的好处是相当于在类内列了一个函数功能表,使我们对类的成员函数的功能一目了然,避免了在各个函数实现的大堆代码中查找函数的定义。在类中声明函数原型的方法与一般函数原型的声明一样,在类外定义函数体的格式如下:

::是类的作用域分辨符,用在此处,放在类名后成员函数前,表明后面的成员函数属于前面的那个类。返回值类型类名::成员函数名(形参表){

函数体;}C++语言程序设计教程第7章类与对象13整理pptClock类中的成员函数可以在类中声明:classClock{private:intH,M,S;public:voidSetTime(inth,intm,ints);//声明成员函数

voidShowTime();//声明成员函数

};

在类外实现成员函数如下:voidClock::SetTime(inth,intm,ints) { H=h,M=m,S=s; };voidClock::ShowTime() {cout<<H<<":"<<M<<":"<<S<<endl;}C++语言程序设计教程第7章类与对象14整理ppt

如果要将类外定义的成员函数编译成内联函数,可以在类外定义函数时,函数的返回类型前加上inline;下面将ShowTime()定义成内联函数,与在类内定义成员函数的效果相同。inlinevoidClock::ShowTime(){cout<<H<<":"<<M<<":"<<S<<endl;}3.类作用域类是一组数据成员和函数成员的集合,类作用域作用于类中定义的特定的成员,包括数据成员与成员函数,类内的每一个成员都具有类作用域。实际上,类的封装作用也就是限制类的成员其访问范围局限于类的作用域之内。C++语言程序设计教程第7章类与对象15整理pptclassClock{private:intH,M,S;public:

ClockAddTime(ClockC2){//形参为Clock类型的变量

ClockT;//函数体中定义了Clock类型的变量

...returnT;//返回类型为Clock类型

}};C++语言程序设计教程第7章类与对象注意:

在成员函数中不仅可以自由使用类的成员,还可以使用该类定义变量(对象),通过变量使用成员。其原因是函数在调用时才在栈内存中建立函数体中的变量(包括实参),这时类已经定义完毕,当然可以使用已定义完整的类类型的变量。16整理ppt7.1.3对象的建立与使用

类相当于一种包含函数的自定义数据类型,它不占内存,是一个抽象的“虚”体,使用已定义的类建立对象就像用数据类型定义变量一样。对象建立后,对象占据内存,变成了一个“实”体。类与对象的关系就像数据类型与变量的关系一样。其实,一个变量就是一个简单的不含成员函数的数据对象。类名对象名;

建立对象的格式如下:其中,对象名可以是简单的标识符,也可以是数组。在例7-1中,使用:

ClockMyClock;

建立了一个Clock型的对象MyClock。C++语言程序设计教程第7章类与对象类名对象名;17整理ppt

在建立对象后,就可以通过对象存取对象中的数据成员,调用成员函数。存取语法如下:例如,通过对象MyClock使用成员函数SetTime()的方式如下:MyClock.SetTime(8,30,30);

至于对数据成员H、M、S的存取,因其存取权限为pravate而被保护,所以不能进行直接存取。C++语言程序设计教程第7章类与对象

对象名.属性对象名.成员函数名(实参1,实参2,…,)注意:为节省内存,编译器在创建对象时,只为各对象分配用于保存各对象数据成员初始化的值,并不为各对象的成员函数分配单独的内存空间,而是共享类的成员函数定义,即类中成员函数的定义为该类的所有对象所共享,这是C++编译器创建对象的一种方法,在实际应用中,我们仍要将对象理解为由数据成员和函数成员两部分组成。18整理ppt7.1.4成员的存取控制

通过设置成员的存取控制属性,使对类成员的存取得到控制,从而达到了信息隐藏的目的。C++的存取控制属性有:公有类型(public)、私有类型(private)和保护类型(protected)。三者的意义如下:表7-1存取控制属性表

C++语言程序设计教程第7章类与对象存取属性意义可存取对象public公开(公有)级该类成员以及所有对象protected保护级该类及其子类成员private私有级该类的成员

类中定义为public等级的成员,可以被该类的任何对象存取,适用于完全公开的数据。而private等级的成员只可被类内的成员存取,适用于不公开的数据。至于protected等级,属于半公开性质的数据,定义为protected等级的成员,可以被该类及其子类存取。关于子类的概念,在以后的章节中讲述。19整理ppt

在Clock类中,H、M、S的存取控制属性为privated。这样,这些数据不能在类外存取而被保护,下列存取方法是错误的:MyClock.M=30;

而成员函数SetTime()、ShowTime()存取控制属性为public,因此在类外可以通过对象存取。 由于private成员被隐藏起来,不能直接在类外被存取,为了取得这些被隐藏的数据,通常在类内定义一个public的成员函数,通过该成员函数存取private成员,而public的成员函数又能在类外被调用。这样通过调用public型的成员函数,间接存取到private成员。这样的函数起到了为private成员提供供外界访问的接口作用。类Clock中成员函数SetTime()、ShowTime()就是存取private数据成员H、M、S的接口。通过接口访问类的数据成员,一方面有效保护数据成员,另一方面又保证了数据的合理性。C++语言程序设计教程第7章类与对象20整理ppt7.2构造函数与析构函数

在定义一个对象的同时,希望能给它的数据成员赋初值――对象的初始化。在特定对象使用结束时,还经常需要进行一些清理工作。C++程序中的初始化和清理工作分别由两个特殊的成员函数来完成,它们就是构造函数和析构函数。C++语言程序设计教程第7章类与对象21整理ppt7.2.1构造函数构造函数(constructor)

构造函数是与类名相同的,在建立对象时自动调用的函数。如果在定义类时,没有为类定义构造函数,编译系统就生成一个默认形式的隐含的的构造函数,这个构造函数的函数体是空的,因此默认构造函数不具备任何功能。如果用户至少为类定义了一个构造函数,C++就不会生成任何默认的构造函数,而是根据对象的参数类型和个数从用户定义的构造函数中选择最合适的构造函数完成对该对象的初始化。作为类的成员函数,构造函数可以直接访问类的所有数据成员,可以是内联函数,可以不带任何参数,可以带有参数表以及默认形参值,还可以重载,用户可以根据不同问题的具体需要,有针对性地设计合适的构造函数将对象初始化为特定的状态。C++语言程序设计教程第7章类与对象22整理ppt例如,将例7-1程序p7-1_b.cpp中的Clock类中添加带有默认形参值的构造函数:

Clock(inth=0,intm=0,ints=0){H=(h>=0&&h<24)?h:0;M=(m>=0&&m<60)?m:0;S=(s>=0&&s<60)?s:0;}执行:ClockMyClock;MyClock.ShowTime();

显示结果为:

0:0:0

这是因为建立对象时调用了Clock(),各个形参被设成了默认值。当执行:

ClockMyClock(9,30,45);MyClock.ShowTime();显示结果为:

9:30:45这是因为建立对象时调用了Clock(9,30,45)C++语言程序设计教程第7章类与对象23整理ppt

构造函数是类的一个成员函数,除了具有一般成员函数的特征之外,还归纳出如下特殊的性质:构造函数的函数名必须与定义它的类同名。构造函数没有返回值。如果在构造函数前加void是错误的。构造函数被声明定义为公有函数。构造函数在建立对象时由系统自动调用。

注意:由于构造函数可以重载,可以定义多个构造函数,在建立对象时根据参数来调用相应的构造函数。如果相应的构造函数没有定义,则出错。例如,若定义例7-1中的构造函数,而不是带默认形参值的构造函数:

Clock(inth,intm,ints){H=(h>=0&&h<24)?h:0;M=(m>=0&&m<60)?m:0;S=(s>=0&&s<60)?s:0;}

定义对象ClockMyClock;时,调用Clock(),而Clock类没有Clock()函数,因而出错。C++语言程序设计教程第7章类与对象24整理ppt7.2.2析构函数

自然界万物都是有生有灭,程序中的对象也是一样。对象在定义时诞生,不同生存期的对象在不同的时期消失。在对象要消失时,通常有一些善后工作需要做,例如:构造对象时,通过构造函数动态申请了一些内存单元,在对象消失之前就要释放这些内存单元。C++用什么来保证这些善后清除工作的执行呢?答案是:析构函数。

析构函数(destructor)也译作拆构函数,是在对象消失之前的瞬间自动调用的函数,其形式是:构造函数名(类名)前加上一个逻辑非运算符~,以示与构造函数相反。析构函数与构造函数的作用几乎正好相反,相当于“逆构造函数”。析构函数也是类的一个特殊的公有函数成员,

C++语言程序设计教程第7章类与对象~构造函数名();25整理ppt7.2.2析构函数析构函数具有以下特点:析构函数没有任何参数,不能被重载,但可以是虚函数,一个类只有一个析构函数。析构函数没有返回值。析构函数名与类名相同,但在类名前加上一个逻辑非运算符“~”,以示与构造函数对比区别。析构函数一般由用户自己定义,在对象消失时由系统自动调用,如果用户没有定义析构函数,系统将自动生成一个不做任何事的默认析构函数。C++语言程序设计教程第7章类与对象注意:在对象消失时的清理工作并不是由析构函数完成,而是靠用户在析构函数中添加清理语句完成。

26整理ppt123456789101112131415/******************************p7_2.cpp**构造函数与析构函数******************************/#include<iostream>usingnamespacestd;classClock

{private:intH,M,S;public:

Clock(inth=0,intm=0,ints=0){ H=h,M=m,S=s; cout<<"constructor:"<<H<<":"<<M<<":"<<S<<endl;}

C++语言程序设计教程第7章类与对象27整理ppt161718192021222324252627

~Clock(){ cout<<"destructor:"<<H<<":"<<M<<":"<<S<<endl;}};ClockC1(8,0,0);ClockC2(9,0,0);voidmain(void){

ClockC3(10,0,0);

ClockC4(11,0,0);}运行结果:constructor:8:0:0constructor:9:0:0constructor:10:0:0constructor:11:0:0destructor:11:0:0destructor:10:0:0C++语言程序设计教程第7章类与对象28整理ppt1234567891011121314151617181920/***********************************p7_3.cpp**基本的字符串类***********************************/#include<iostream>usingnamespacestd;classString

{private:char*Str; intlen; public:

voidShowStr(){ cout<<"string:"<<Str<<",length:"<<len<<endl;}

String(){ len=0; Str=NULL;}C++语言程序设计教程第7章类与对象29整理ppt21222324252627282930313233343536373839404142

String(constchar*p){ len=strlen(p); Str=newchar[len+1]; strcpy(Str,p);}

~String(){ if(Str!=NULL) { delete[]Str; Str=NULL; }}};voidmain(void){chars[]="ABCDE"; Strings1(s); Strings2("123456"); s1.ShowStr(); s2.ShowStr();}运行结果:string:ABCDE,length:5string:123456,length:6C++语言程序设计教程第7章类与对象30整理ppt7.2.3拷贝构造函数

拷贝构造函数是与类名相同,形参是本类的对象的引用的函数,在用已存在对象初始化新建立对象时调用。类的拷贝构造函数一般由用户定义,如果用户没有定义拷贝构造函数,系统就会自动生成一个默认函数,这个默认拷贝构造函数的功能是把初始值对象的每个数据成员的值依次复制到新建立的对象中。因此,也可以说是完成了同类对象的克隆(Clone)。这样得到的对象和原对象具有完全相同的数据成员,即完全相同的属性。

C++语言程序设计教程第7章类与对象31整理ppt

用户可以也可以根据实际问题的需要定义特定的拷贝构造函数来改变缺省拷贝构造函数的行为,以实现同类对象之间数据成员的传递。如果用户自定义了拷贝构造函数,则在用一个类的对象初始化该类的另外一个对象时,自动调用自定义的拷贝构造函数。定义一个拷贝构造函数的一般形式为:

拷贝构造函数在用类的一个对象去初始化该类的另一个对象时调用,以下三种情况相当于用一个已存在的对象去初始化新建立的对象,此时,调用拷贝构造函数:

①当用类的一个对象去初始化该类的另一个对象时。

②如果函数的形参是类的对象,调用函数时,将对象作为函数实参传递给函数的形参时。

③如果函数的返回值是类的对象,函数执行完成,将返回值返回时。类名(类名&

对象名){…};C++语言程序设计教程第7章类与对象32整理ppt12345678910111213141516171819/******************************p7_4.cpp**构造拷贝构造函数******************************/#include<iostream>usingnamespacestd;classClock{private:intH,M,S;public:

Clock(inth=0,intm=0,ints=0){ H=h,M=m,S=s; cout<<"constructor:"<<H<<":"<<M<<":"<<S<<endl;}

~Clock(){ cout<<"destructor:"<<H<<":"<<M<<":"<<S<<endl;}C++语言程序设计教程第7章类与对象33整理ppt20212223242526272829303132333435363738394041424344

Clock(Clock&p){cout<<"copyconstructor,beforecall:"<<H<<":"<<M<<":"<<S<<endl;H=p.H;M=p.M;S=p.S;}

voidShowTime(){cout<<H<<":"<<M<<":"<<S<<endl;}};

Clockfun(ClockC){returnC;}voidmain(void){ClockC1(8,0,0);ClockC2(9,0,0);ClockC3(C1);fun(C2);ClockC4;C4=C2;}

运行结果:constructor:8:0:0constructor:9:0:0copyconstructor,beforecall:-858993460:-858993460:-858993460copyconstructor,beforecall:1310592:4200534:1310568copyconstructor,beforecall:-858993460:-858993460:-858993460destructor:9:0:0destructor:9:0:0constructor:0:0:0destructor:9:0:0destructor:8:0:0destructor:9:0:0destructor:8:0:0注意:拷贝构造函数只是在用一个已存在的对象去初始化新建立的对象时调用,在对象进行赋值时,拷贝构造函数不被调用。用一个常量初始化新建立的对象时,调用构造函数,不调用拷贝构造函数。建立对象时,构造函数与拷贝构造函数有且仅有一个被调用。C++语言程序设计教程第7章类与对象34整理ppt7.2.4浅拷贝与深拷贝

在默认的拷贝构造函数中,拷贝的策略是直接将原对象的数据成员值依次拷贝给新对象中对应的数据成员,如前面示例p7_4.cpp中定义的拷贝函数所示,那么我们为何不直接使用系统默认的拷贝构造函数,何必又自己定义一个拷贝构造函数呢?但是,有些情况下使用默认的拷贝构造函数却会出现意想不到的问题。

例如,使用程序p7_3.cpp中定义的String类,执行下列程序系统就会出错:

voidmain(){Strings1("123456");Strings2=s1;}C++语言程序设计教程第7章类与对象35整理ppt

为什么会出错呢?程序中首先创建对象s1,为对象s1分配相应的内存资源,调用构造函数初始化该对象,然后调用系统缺省的拷贝构造函数将对象s1拷贝给对象s2,这一切看来似乎很正常,但程序的运行却出现异常!原因在于默认的拷贝构造函数实现的只能是浅拷贝,即直接将原对象的数据成员值依次拷贝给新对象中对应的数据成员,并没有为新对象另外分配内存资源。这样,如果对象的数据成员是指针,两个指针对象实际上指向的是同一块内存空间。

当执行Strings2=s1时,默认的浅拷贝构造函数进行的是下列操作:

s2.len=s1.len;s2.Str=s1.Str;

实际上是将s1.Str的地址赋给了s2.Str,并没有为s2.Str分配内存,执行Strings2=s1;后,对象s2析构,释放内存,然后对象s1析构,由于s1.Str和s2.Str所占用的是同一块内存,而同一块内存不可能释放两次,所以当对象s1析构时,程序出现异常,无法正常执行和结束。由此可见,在某些情况下,浅拷贝会带来数据安全方面的隐患。C++语言程序设计教程第7章类与对象36整理ppt

当类的数据成员中有指针类型时,我们就必须定义一个特定的拷贝构造函数,该拷贝构造函数不仅可以实现原对象和新对象之间数据成员的拷贝,而且可以为新的对象分配单独的内存资源,这就是深拷贝构造函数。C++语言程序设计教程第7章类与对象37整理ppt【例7-5】带深拷贝构造函数的字符串类。在程序p7_3中的String类中,加入下列拷贝构造函数,构成了带深拷贝函数的字符串类。String(String&r){ len=r.len; if(len!=0) {

Str=newchar[len+1];strcpy(Str,r.Str);

}}下列程序能正常运行。voidmain(void){

Strings1("123456"); Strings2=s1; s1.ShowStr(); s2.ShowStr();}C++语言程序设计教程第7章构造数据类型注意:在重新定义拷贝构造函数后,默认拷贝构造函数与默认构造函数就不存在了,如果在此时调用默认构造函数就会出错。在重新定义构造函数后,默认构造函数就不存在了,但默认拷贝构造函数还存在。在对象进行赋值时,拷贝构造函数不被调用。此时进行的是结构式的拷贝。38整理ppt

类相当于一种包含函数的自定义数据类型,它不占内存,是一个抽象的“虚”体,使用已定义的类建立对象就像用数据类型定义变量一样。对象建立后,对象占据内存,变成了一个“实”体。对象如同一般变量,占用一块连续的内存区域,因此可以使用一个指向对象的指针来访问对象,即对象指针,它指向存放该对象的地址。可用类来定义对象指针变量,通过对象指针来访问对象的成员。

C++语言程序设计教程第7章类与对象7.3对象的使用39整理ppt7.3.1对象指针

对象指针遵循一般变量指针的各种规则,其语法定义形式如下:如同通过对象名访问对象的成员一样,使用对象指针也只能访问该类的公有数据成员和函数成员,但与前者使用“.”运算符不同,对象指针采用“->”运算符访问公有数对象指针名->数据成员名例如:

Clock

*Cp;ClockC1(8,0,0);Clock*Cp;Cp=&C1;Cp->ShowTime();C++语言程序设计教程第7章类与对象

类名*对象指针名;

对象指针名->数据成员名或:对象指针名->成员函数名(参数表)40整理ppt

在C++中,对象指针可以作为成员函数的形参,一般而言,使用对象指针作为函数的参数要比使用对象作为函数的参数更普遍一些,因为使用对象指针作为函数的参数有如下两点好处:(1)实现地址传递。通过在函数调用时将实参对象的地址传递给形参指针对象,使形参指针对象和实参对象指向同一内存地址,这样,对象指针所指向对象的改变也将同样影响着实参对象,从而实现信息的双向传递。(2)

使用对象指针效率高使用对象指针传递的仅仅是对应实参对象的地址,并不需要实现对象之间的副本拷贝,这样就会减小时空开销,提高运行效率。C++语言程序设计教程第7章类与对象41整理ppt123456789101112131415161718/******************************p7_6.cpp**带时间加法的时钟类******************************/#include<iostream>usingnamespacestd;classClock{private:intH,M,S;public:

voidSetTime(inth,intm,ints){ H=h,M=m,S=s;}

voidShowTime(){cout<<H<<":"<<M<<":"<<S<<endl;}C++语言程序设计教程第7章类与对象【例7-6】时间加法。时间加法有两种,一种是时钟加秒数,另一种是时钟加时、分、秒。采用重载函数实现这两种加法。42整理ppt192021222324252627282930313233343536

Clock(inth=0,intm=0,ints=0){ H=h,M=m,S=s;}

Clock(Clock&p){ H=p.H,M=p.M,S=p.S;}voidTimeAdd(Clock*Cp);voidTimeAdd(inth,intm,ints);voidTimeAdd(ints);};voidClock::TimeAdd(Clock

*Cp){H=(Cp->H+H+(Cp->M+M+(Cp->S+S)/60)/60)%24;M=(Cp->M+M+(Cp->S+S)/60)%60;S=(Cp->S+S)%60;}C++语言程序设计教程第7章类与对象函数重载函数原型声明对象指针43整理ppt373839404142434445464748495051525354555657voidClock::TimeAdd(inth,intm,ints){H=(h+H+(m+M+(s+S)/60)/60)%24;M=(m+M+(s+S)/60)%60;S=(s+S)%60; }voidClock::TimeAdd(ints){H=(H+(M+(S+s)/60)/60)%24;M=(M+(S+s)/60)%60;S=(S+s)%60;}voidmain(){ClockC1;ClockC2(8,20,20);C1.TimeAdd(4000);C1.ShowTime();C2.TimeAdd(&C1);C2.ShowTime();}运行结果:1:6:409:27:0

C++语言程序设计教程第7章类与对象函数重载函数重载44整理ppt7.3.2对象引用

对象引用就是对某类对象定义一个引用,其实质是通过将被引用对象的地址赋给引用对象,使二者指向同一内存空间,这样引用对象就成为了被引用对象的“别名”。对象引用的定义方法与基本数据类型变量引用的定义是一样的。定义一个对象引用,并同时指向一个对象的格式为:

类名&对象引用名=被引用对象;

C++语言程序设计教程第7章类与对象注意:对象引用与被引用对象必须是同类型的。除非是作为函数参数与函数返回值,对象引用在定义时必须要初始化。定义一个对象引用并没有定义一个对象,所以不分配任何内存空间,不调用构造函数。45整理ppt对象引用的使用格式为:

例如:

ClockC1(8,20,20);Clock&Cr=C1;//定义了C1的对象引用Cr。

Cr.ShowTime();//通过对象引用使用对象的成员运行结果为:

8:20:20C++语言程序设计教程第7章类与对象7.3.2对象引用

对象引用名.

数据成员名或:对象引用名.

成员函数名(参数表)46整理ppt对象引用的优点:对象引用通常用作函数的参数,它不仅具有对象指针的优点,而且比对象指针更简洁,更方便,更直观。将p7_6.cpp中添加如下函数:

voidClock::TimeAdd(Clock&Cr){ H=(Cr.H+H+(Cr.M+M+(Cr.S+S)/60)/60)%24; M=(Cr.M+M+(Cr.S+S)/60)%60;S=(Cr.S+S)%60;}

将C2.TimeAdd(&C1);替换为:C2.TimeAdd(C1);

运行结果与p7_6.cpp一样。C++语言程序设计教程第7章类与对象7.3.2对象引用47整理ppt

对象数组是以对象为元素的数组。对象数组的定义、赋值、引用与普通数组一样,只是数组元素与普通数组的数组元素不同。对象数组定义格式如下:

其中,类名指出该数组元素所属的类,常量表达式给出某一维元素的个数。

与结构数组不同,对象数组初始化需要使用构造函数完成,以一个大小为n的一维数组为例,对象数组的初始化格式如下:C++语言程序设计教程第7章类与对象7.3.3对象数组类名对象数组名[常量表达式n],...,[常量表达式2][常量表达式1];数组名[n]={构造函数(数据成员1初值,数据成员2初值,…),构造函数(数据成员1初值,数据成员2初值,…),…构造函数(数据成员1初值,数据成员2初值,…)};注意:不带初始化表的对象数组,其初始化靠调用不带参数的构造函数完成。

48整理ppt

以一个m维数组为例,对象数组元素的存取格式如下:

C++语言程序设计教程第7章类与对象

对象数组名[下标表达式1][下标表达式2]…[下标表达式m].数据成员名或:对象数组名[下标表达式1][下标表达式2]…[下标表达式m].成员函数名(参数表)【例7-7】计算一个班学生某门功课的总评成绩。分析:首先设计一个类Score,这个类的数据成员为一个学生的学号、姓名、平时成绩、期末考试成绩,成员函数有求总评成绩、显示成绩。然后,定义一个对象数组存储一个班学生的成绩。最后,通过逐一调用数组元素的成员函数求每个学生的总评成绩。49整理ppt123456789101112131415161718192021/******************************************p7_7.cpp**求一个班学生某门功课的总评成绩*******************************************/#include<iostream>usingnamespacestd;constintMaxN=100;constdoubleRate=0.6;//平时成绩比例classScore{private: longNo;//学号

char*Name;//姓名

intPeace;//平时成绩

intFinal;//期末考试成绩

intTotal;//总评成绩

public:Score(long=0,char*=NULL,int=0,int=0,int=0);//构造函数

voidCount();//计算总评成绩

voidShowScore();//显示成绩};C++语言程序设计教程第7章类与对象50整理ppt22232425262728293031323334353637Score::Score(longno,char*name,intpeace,intfinal,inttotal)//构造函数{No=no;Name=name;Peace=peace;Final=final;Total=total;}voidScore::Count(){Total=Peace*Rate+Final*(1-Rate)+0.5;}voidScore::ShowScore(){cout<<No<<"\t"<<Name<<"\t"<<Peace<<"\t"<<Final<<"\t"<<Total<<endl;}C++语言程序设计教程第7章类与对象51整理ppt38394041424344454647484950voidmain(){ScoreClassScore1[3];ScoreClassScore2[3]={Score(200607001,"Tom",80,79), Score(200607002,"John",90,85),Score(200607003,"Wilson",70,55)};for(inti=0;i<3;i++)ClassScore2[i].Count();for(i=0;i<3;i++)ClassScore2[i].ShowScore();}运行结果:200607001Tom807980200607002John908588200607003Wilson705564C++语言程序设计教程第7章类与对象对象数组52整理ppt7.3.4动态对象动态对象:动态对象是指编程者随时动态建立并可随时消失的对象。建立动态对象采用动态申请内存的语句new,删除动态对象使用delete语句。建立一个动态对象的格式为:

对象指针=new类名(初值表);

C++语言程序设计教程第7章类与对象注意:对象指针的类型应与类名一致。动态对象存储在new语句从堆申请的空间中。建立动态对象时要调用构造函数,当初值表缺省时调用默认的构造函数。53整理ppt例如:

Clock*Cp;//建立对象指针

Cp=newClock;//建立动态对象,调用默认构造函数Clock()。

Cp->ShowTime();//结果为0:0:0Cp=newClock(8,0,0);//建立动态对象,调用构造函数Clock(int,int,int)

Cp->ShowTime();//结果为8:0:0C++语言程序设计教程第7章类与对象7.3.4动态对象注意:

函数体内的局部对象在函数调用时建立,在函数调用完后消失;全局对象则在程序执行时建立,执行完成后才消失;这些对象在何时建立,何时消失是C++规定好了的,不是编程者能控制的。54整理ppt

在堆中建立的动态对象不能自动消失,需要使用delete语句删除对象,格式为:在删除动态对象时,释放堆中的内存空间,在对象消失时,调用析构函数。例如:

deleteCp;//删除Cp指向的动态对象

动态对象的一个重要的使用方面是用动态对象组成动态对象数组,建立一个一维动态对象数组的格式为:

删除一个动态对象数组的格式为:在建立动态对象数组时,要调用构造函数,调用的次数与数组的大小相同;删除对象数组时,要调用析构函数,调用次数与数组的大小相同。C++语言程序设计教程第7章类与对象delete对象指针;

对象指针=new

类名[数组大小];delete[]

对象指针;55整理ppt将p7_7.cpp改为用动态对象数组实现如下:C++语言程序设计教程第7章类与对象7.3.4动态对象

Score::SetScore(longno,char*name,intpeace,intfinal,inttotal){No=no;Name=name;Peace=peace;Final=final;Total=total;}56整理ppt将p7_7.cpp改为用动态对象数组实现如下:C++语言程序设计教程第7章类与对象SetScore()函数为动态数组设置初值。voidmain(){Score*ClassScore;ClassScore=newScore[3];ClassScore[0].SetScore(200607001,"Tom",80,79),ClassScore[1].SetScore(200607002,"John",90,85),ClassScore[2].SetScore(200607003,"Wilson",70,55);for(inti=0;i<3;i++)ClassScore[i].Count();for(i=0;i<3;i++)ClassScore[i].ShowScore();delete[]ClassScore;}57整理ppt7.3.5This指针

一个类的成员函数中,有时希望引用调用的它对象,对此,C++采用隐含的this指针来实现。

this指针是一个系统预定义的特殊指针,指向当前对象,表示当前对象的地址。C++语言程序设计教程第7章类与对象123456例如:voidClock::SetTime(inth,intm,ints){H=h,M=m,S=s;this->H=h,this->M=m,this->S=s;(*this).H=h,(*this).M=m,(*this).S=s;}//语句3、4、5是等效的为了与类的数据成员H、M、S区别,将SetTime的形参名设为h、m、s。如果使用this指针,就可以凭this指针区分本对象的数据成员与其他变量。58整理ppt

系统利用this指针明确指出成员函数当前操作的数据成员所属的对象。实际上,当一个对象调用其成员函数时,编译器先将该对象的地址赋给this指针,然后调用成员函数,这样成员函数对对象的数据成员进行操作时,就隐含使用了this指针。一般而言,通常不直接使用this指针来引用对象成员,但在某些少数情况下,可以使用this指针,如:重载某些运算符以实现对象的连续赋值等。C++语言程序设计教程第7章类与对象1234//使用this指针重新设计的SetTime()成员函数如下:

voidClock::SetTime(intH,intM,intS){this->H=H,this->M=M,this->S=S;}注意:this指针不是调用对象的名称,而是指向调用对象的指针的名称。this的值不能改变,它总是指向当前调用对象。59整理ppt7.3.6对象组合

组合概念体现的是一种包含与被包含的关系,在语义上表现为“ispartof”的关系,即在逻辑上A是B的一部分。在C++程序设计中,类的组合用来描述一类复杂的对象,在类的定义中,它的某些属性,往往是另一个类的对象,而不是像整型、浮点型之类的简单数据类型,也就是“一个类内嵌其它类的对象作为成员”,将对象嵌入到类中的这样一种描述复杂类的方法,我们称之为“类的组合”,一个含有其他类对象的类称为组合类,组合类的对象称为组合对象。组合类定义的步骤为:先定义成员类,再定义组合类。C++语言程序设计教程第7章类与对象60整理ppt7.3.6对象组合【例7-8】计算某次火车的旅途时间。分析:某次火车有车次、起点站、终点站、出发时间、到达时间。前面定义的Clock类正具有时间特性,因此,可以利用Clock对象组合成一个火车旅途类TrainTrip。假定火车均为24小时内到达,旅途时间为到达时间减出发时间。用空方框表示类,灰框表示对象,组合类可以表示为空框包含灰框。设计TrainTrip类的示意图与成员构成图如图7-4:C++语言程序设计教程第7章类与对象61整理ppt1234567891011121314151617181920/******************************p7_8.cpp**计算火车旅途时间的组合类******************************/#include<iostream>usingnamespacestd;classClock{private:intH,M,S;public:

voidShowTime(){cout<<H<<":"<<M<<":"<<S<<endl;}

voidSetTime(intH=0,intM=0,intS=0){this->H=H,this->M=M,this->S=S;}

Clock(intH=0,intM=0,intS=0){this->H=H,this->M=M,this->S=S;}C++语言程序设计教程第7章类与对象Clock类62整理ppt232425262728293031323334353637383940intGetH(){returnH; }intGetM(){returnM; }intGetS(){returnS; }};classTrainTrip{private:char*TrainNo;//车次

ClockStartTime;//出发时间

ClockEndTime;//到达时间public:

TrainTrip(char*TrainNo,ClockS,ClockE){this->TrainNo=TrainNo;StartTime=S; EndTime=E;}C++语言程序设计教程第7章类与对象组合类63整理ppt4142434445464748495051525354555657585960

ClockTripTime(){inttH,tM,tS;//临时存储小时、分、秒数

intcarry=0;//借位

ClocktTime;//临时存储时间

(tS=EndTime.GetS()-StartTime.GetS())>0?carry=0:tS+=60,carry=1;(tM=EndTime.GetM()

温馨提示

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

最新文档

评论

0/150

提交评论