2018数据结构与算法设计描述模块_第1页
2018数据结构与算法设计描述模块_第2页
2018数据结构与算法设计描述模块_第3页
2018数据结构与算法设计描述模块_第4页
2018数据结构与算法设计描述模块_第5页
已阅读5页,还剩75页未读 继续免费阅读

下载本文档

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

文档简介

模块三C++类及其对象的封装性C++面向对象程序设计本模块主要内容2类的声明和对象定义类的成员函数对象成员的引用构造函数和析构函数对象指针动态存储类的声明和对象定义3C++类及其对象的封装性类是具有相同属性和行为的一组对象的集合,它为属于该类的全部对象提供了统一的抽象描述,其内部包括属性和行为两个主要部分。利用类可以实现数据的封装、隐藏、继承与派生。利用类易于编写大型复杂程序,其模块化程度比C中采用函数更高。类的声明和对象定义4C++类及其对象的封装性类是对象共性特征的抽象,对象的类型称为类,类是对象的模板,对象是类的具体实例;先声明一个类,再定义对象,类是抽象的,不占用内存,对象是具体的,占用实际的存储空间;可以看作是一种特殊的构造数据类型,是结构体的扩充形式;类是数据和对这些数据进行操作的函数的封装体,是包括数据和函数的数据类型;类的定义包括数据和函数的定义,类中的数据和函数都是类的成员;在C++中,类用class来构造。类的声明//声明结构体类型

struct

Student{int

num;char

name[20]

;char

sex;};//定义2个结构变量Student

stud1,stud2class

Student

//声明类,以class开头{int

num;char

name[20]

;char

sex;

//以上3行是数据成员void

display()

//成员函数{cout<<“num:”<<num<<endl;cout<<“name

:”

<<name<<endlcout<<“sex:”<<sex<<endl;

}};//定义Student类的对象stud1,stud2;5Student

stud1,stud2;6类的声明和对象定义上述类定义中未限定成员的访问属性,对象stud1的数据和函数都是private的,数据安全了。但外界不能调用stud1中的函数和功能,因为没有提供类的对外的接口,类有何用?不能把类中的全部成员与外界隔离,一般将类中的数据隐藏起来,声明为私有的(

private

),把成员函数作为对外界的接口,声明为公有的(public)。例如,上述类声明改为:class

Student

//声明类类型{private:

//声明以下部分为私有

int

num;char

name[20]

;char

sex;public:

//声明以下部分为公有

void

display(){cout<<“num:”<<num<<endl;cout<<“name:”<<name<<endl;cout<<“sex:”<<sex<<endl;

}};Student

stud1,stud2;7在C++中,定义类的一般格式为:class

类名{private://私有类型只限于通过自己的成员函数//来访问,即只有类本身能够访问它数据成员和成员函数说明public://公有类型提供了类的外部接口,允许类//的使用者来访问它数据成员和成员函数说明protected://保护类型只允许本类成员函数或派生//类成员函数访问,用于类的继承和派生数据成员和成员函数};公有类型成员8在关键字public后面声明,它们是类与外部的接口,任何外部函数都可以访问公有类型数据和函数。类的声明和对象的定义私有类型成员9在关键字private后面声明,只允许本类中的函数访问,而类外部的任何函数都不能访问。如果紧跟在类名称的后面声明私有成员,则关键字private可以省略。类的声明和对象的定义保护类型10与private类似,其差别表现在继承与派生时对派生类的影响不同。类的声明和对象的定义在类的定义中应注意以下几点:111、“类名”是一个合法的标识符;2、关键字private,public和protected说明类成员的三种访问权限;3、{}以内的部分是“类内”,{}以外的部分为“类外”;4、类定义的声明部分在“类内”,类的成员函数既可以在“类内”定义,也可以在“类外”定义;5、在“类内”不允许对所声明的数据成员进行初始化,类的数据成员的类型可以任意。12//声明一个类class

CArea{private://私有部分int

x,

y,

area;public:

//公有部分void

squarea(int

vx,

int

vy);};例题3.

1数据成员13与一般的变量声明相同,但需要将它放在类的声明体中。类的声明和对象的定义成员函数14在类中说明原形,可以在类外给出函数体实现,并在函数名前使用类名加以限定。也可以直接在类中给出函数体,形成内置成员函数。允许声明重载函数和带默认形参值的函数。类的声明和对象的定义类的成员class

Clock{public:void

SetTime(int

NewH,

int

NewM,int

NewS);void

ShowTime();private:int

Hour,

Minute,

Second;};成员数据成员函数15类的声明和对象的定义void

Clock

::

SetTime(int

NewH,

int

NewM,int

NewS){Hour=NewH;Minute=NewM;Second=NewS;}void

Clock

::

ShowTime(){cout<<Hour<<":"<<Minute<<":"<<Second;}16类的声明和对象的定义类和结构体的异同1、均为构造类型;2、结构体用struct、类用class作为标识;2、结构体中的成员只有数据成员,且访问权限默认为public的;3、类的成员包括数据和函数,且访问权限可以设置为private、public和protected的;4、结构没有实现数据封装,数据可以被任何外部函数访问。类实现了数据封装,可以将数据限定为只能被本身的成员函数访问。17类的声明和对象的定义18定义对象的方法1、先声明类类型,然后再定义对象:如

Student

stud1,stud2;在声明类类型之后,定义对象有2种方法:class

类名对象名;如

class

Student

stud1,stud2;类名对象名;如

Student

stud1,stud2;类的声明和对象的定义定义对象的方法2、在声明类类型的同时定义对象://声明类类型//先声明公用部分class

Student{

public:void

display(){

cout<<“num:”<<num<<endl;cout<<“name:”<<name<<endl;cout<<“sex:”<<sex<<endl;

}private:

//后声明私有部分

intnum;char

name[20]

;char

sex;}stud1,stud2;//定义Student类的对象stud1,stud192类的声明和对象的定义20定义对象的方法3、不出现类名,直接定义对象://声明类类型//声明公用部分//声明私有部分//声明保护部分class{

public:……private:……protected:……}stud1,stud2;//定义对象stud1,stud2定义多个对象时,对象名之间用逗号隔开;对象名可以是一般的对象、指向对象的指针或引用名,也可以是对象数组。类的声明和对象的定义例3.221定义一个日期类CDate,再创建一个生日对象。class

CDate{int

year;int

month;int

day;public:voidSetDate(int,int,int);void

ShowDate();}myBirthday;

//同时创建对象myBirthday或者定义类之后:CDate

myBirthday,*p,q[5];类的声明和对象的定义类的成员函数C++类及其对象的封装性类的成员函数具有一般函数的性质,它同时属于某个类的成员,出现在类定义体中,可被限定为具有

private、public和protected三种访问属性;成员函数可以访问本类中的任何成员(包括private和public特性),可以引用在本作用域中有效的数据;private属性的成员函数只能被本类其它的成员函数调用,不能被外界调用;public属性的成员函数可以被外界调用,它是类的对外接口。22在类外定义成员函数23类的成员函数类的成员函数可以在“类内”声明,在“类外”定义;类外定义成员函数的一般形式如下:

返回值类型

类名::成员函数名(参数表){

……

//函数体}其中::是作用域运算符。例3.324//公用成员函数原型声明//以上3行是私有数据成员class

Student

{public:void

display(

);private:intnum;string

name;charsex;};void

Student

::display()

//在类外定义成员函数{ cout<<“num:”<<

num

<<

endl;cout

<<“name:”<<

name

<<

endl;cout

<<“sex:”<<

sex

<<

endl;

}Student

stud1,stud2;

//定义2个类对象类的成员函数25内置(inline)成员函数有些简单的成员函数可以直接在类定义中定义,在类定义体中定义的成员函数称为内置函数(内联函数);内置函数可以减少函数调用时的内存开销,不用记录函数调用返回地址,只将代码嵌入到函数调用点内置函数的定义有两种方法:1、隐式定义将成员函数的定义体放在“类内”中。2、显式定义在“类内”声明,在“类外”定义时在函数名前加关键字inline。类的成员函数内置成员函数举例(一)26class

Point{public:void

Init(int

initX,int

initY){X=initX;Y=initY;}int

GetX()

{return

X;}int

GetY()

{return

Y;}private:int

X,Y;};类的成员函数内置成员函数举例(二)27class

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

Point::GetX(){return

X;}inline

int

Point::GetY(){return

Y;}29成员函数的存储方式定义类对象时,系统会为每个对象分配存储空间,包括为类对象的数据和函数代码分配空间;如果定义同类的10个对象,那么如何为这10个对象分配不同的空间?10

个同类对象占用存储单元的情况类的成员函数30成员函数的存储方式为了节约内存,只用一段存储空间来存放10个对象拥有的共同的函数代码段,如下图:10

个同类对象成员函数的存储方式C++规定:对象占用的存储空间只是对象数据成员占用的存储空间,可用sizeof函数验证;共同的成员函数代码存储在对象空间之外。类的成员函数31成员函数的存储方式调用不同对象的成员函数时都是执行同一段函数代码,但其执行结果一般不同(常与数据有关);不同对象使用同一段函数代码,它们如何对不同对象中的数据进行操作呢?C++专门为此设计了一个this指针,用来指向不同的对象;调用哪个对象,this就指向哪个对象,就访问它的成员。类的成员函数类中成员的访问方式32类中成员互访直接使用成员名类外访问使用“对象名.成员名”方式访问public属性的成员类的成员函数例:类的应用举例33#include<iostream>using

namespace

std;class

Clock{......//类的声明略}//......类的实现略

void

main(void){

Clock

myClock;myClock.SetTime(8,30,30);myClock.ShowTime();}类的成员函数对象成员的引用34访问对象中的成员有3种方法:1、通过对象名和成员运算符访问对象中的成员,即:对象名.数据成员名or

对象名.成员函数名(参数表)例如:stud1.

num

=1001;stud1.

display();//设num和display函数为public成员类的成员函数35对象成员的引用定义一个日期类,使其具有输出当前日期的功能。例gf4:引用对象的成员2、通过指向对象的指针访问对象中的成员,即:对象指针->数据成员名or

对象指针->成员函数名(参数表)例如:Time

t,*p=&t;cout<<p->hour;//hour是t中的成员3、通过对象的引用变量访问对象中的成员。类的成员函数构造函数36构造函数的作用是在对象被创建时使用特定的值构造对象,或者说将对象初始化为一个特定的状态。在对象创建时由系统自动调用。如果程序中未声明,则系统自动产生出一个默认形式的构造函数。允许为内置函数、重载函数、带默认形参值的函数。构造函数和析构函数构造函数37构造函数和析构函数构造函数的名字必须与类名相同;构造函数一般声明为public,无返回值,无需定义返回类型;构造函数是系统自动调用的,且执行一次;构造函数不能被继承,但允许重载(overloading);构造函数的功能是对对象进行初始化,一般构造函数用于对象的初始化,每当对象被声明时对数据成员做初始化,不做赋值外的事情。构造函数的几种形式38构造函数和析构函数构造函数可为内联函数,可以为无参数或带参数,还可以缺省参数,例如:无参的构造函数参数化的构造函数缺省参数的构造函数多构造函数拷贝构造函数class

CArea{public:CArea(

){x=0;

y=0;}

//无参数的构造函数CArea

(int

rx,

int

ry=0);CArea(float

rr)

{rr=0;}//带缺省参数的构造函数//带一个参数的构造函数CArea(float

rr,char

*ra);

//带两个参数的构造函数};在类中声明的多种构造函数:例39构造函数举例40class

Clock{public:Clock

(int

NewH,int

NewM,int

NewS);//构造函数

void

SetTime(int

NewH,int

NewM,int

NewS);void

ShowTime();private:int

Hour,Minute,Second;};构造函数和析构函数构造函数的实现:31Clock::Clock(int

NewH,

int

NewM,

int

NewS){Hour=

NewH;Minute=

NewM;Second=

NewS;}建立对象时构造函数的作用:void

main(){Clock c

(0,0,0);//隐含调用构造函数,将初始值作为实参。

c.ShowTime();}例gf5

在类中定义构造函数。42构造函数的使用何时调用构造函数?在类对象进入其作用域时调用构造函数;构造函数没有返回值,不要在定义构造函数时声明类型;构造函数不需要用户调用,也不能被用户调用;在构造函数体中,不仅可以对数据成员赋初值,还可以包含其他语句如cout;如果用户没有定义构造函数,C++系统会自动生成一个构造函数,其函数体为空,不执行初始化操作;要想初始化一个对象,需要重新定义构造函数,否则对象的状态将是随机的。构造函数和析构函数43带参数的构造函数定义对象时,通过不同参数值的传递实现不同对象的不同初始化,可以使用带参数的构造函数;一般格式:构造函数名(类型1

形参1,类型2

形参2,……)用户不能显式地调用构造函数,也无法采用常规的调用函数的方法给出实参(如fun(a,b))。实参只能在定义对象时给出,定义对象的一般格式:类名对象名(实参1,实参2,……);例gf6:有两个长方体,长、宽、高分别为:(1)12,25,30;(2)15,30,21。用带参数的构造函数编写程序求其体积。构造函数和析构函数使用参数初始化表44在定义对象时,可使用参数初始化表来实现对数据成员的初始化,在函数首部实现:Box::Box(int

h,

int

w,

int

len):

height(h),

width(w),length(len)

{

}其含义是:用形参h的值初始化数据成员height,用形参w的值初始化数据成员width,用形参len的值初始化数据成员length。构造函数和析构函数构造函数的重载45一个类可以定义多个构造函数,使用户选用不同的方式完成对象数据的初始化;重载的所有构造函数同名,但其参数类型、参数个数必须有所区别。构造函数和析构函数46重载构造函数的例子例,可以在类中声明的多种构造函数:class

CArea{public:CArea(

){x=0;

y=0;}

//无参数的构造函数CArea

(int

rx,

int

ry=0);

//带缺省参数的构造函数CArea(float

rr)

{rr=0;}

//带一个参数的构造函数

CArea(float

rr,char

*ra);

//带两个参数的构造函数};例gf7

在例gf6的基础上定义两个构造函数,其中一个无参数,一个有参数。缺省构造函数47在调用构造函数时不必给出实参的构造函数,称为默认构造函数(DefaultConstructor)或缺省构造函数;无参数的构造函数属于缺省构造函数;如果在定义对象时选用无参构造函数,应按以下形式定义对象:Box

box1;//调用无参构造函数建立对象在一个类中可以包含多个构造函数,但是在创建每个对象时,只执行其中一个匹配版本的构造函数。构造函数和析构函数默认形参值的作用48函数在声明时可以预先给出默认的形参值,调用时如给出实参,则采用实参值,否则采用预先给出的默认形参值。例如:int

add(int

x=5,int

y=6){

return

x+y;}void

main(void){ add(10,20);

//10+20add(10);add(

);//10+6//5+6}默认形参值的说明次序49默认形参值必须从右向左顺序声明,并且在默认形参值的右面不能有非默认形参值的参数。因为调用时实参取代形参是从左向右的顺序。例:int

add(int

x,int

y=5,int

z=6);//正确

int

add(int

x=1,int

y=5,int

z);//错误

int

add(int

x=1,int

y,int

z=6);//错误默认形参值与函数的调用位置调用出现在函数体实现之前时,默认形参值必

须在函数原形中给出;而当调用出现在函数体

实现之后时,默认形参值需在函数实现时给出。例:int

add(int

x=5,int

y=6);void

main(void){

add();//调用在实现前}int

add(int

x,int

y){ return

x+y;

}int

add(int

x=5,int

y=6){

return

x+y;

}void

main(void){

add();

//调用在实现后}50默认形参值的作用域51在相同的作用域内,默认形参值的说明应保持唯一,但如果在不同的作用域内,允许说明不同的默认形参。例:int

add(int

x=1,int

y=2);void

main(void){ int

add(int

x=3,int

y=4);add();

//使用局部默认形参值(实现3+4)}void

fun(void){

...add();

//使用全局默认形参值(实现1+2)}使用默认参数的构造函数52使用默认参数的构造函数,如果创建对象时不需要通过传递参数来初始化对象,可以使用它。例gf8:将例gf7的构造函数改为含默认值参数值,长、宽、高的默认值均为10。构造函数和析构函数

应该在声明构造函数时指定参数的默认值,而不能只在定义构造函数时指定默认值;

如果构造函数的全部参数都指定了默认值,则在

定义对象时可以不给出,或给出一个、几个实参;

在一个类中定义了全部默认参数的构造函数后,不能再定义重载构造函数,否则会出现二义性。使用默认参数的构造函数注意:在构造函数中使用默认参数提供了建立对象的多种初始化方法,相当于多个重载的构造函数;Box(int

=10,int

=10,int

=10);//指定全部参数为默认参数53//声明无参构造函数,是重载构造函数//声明有2个参数的构造函数Box();Box(int,int);若有以下语句:

Box

box1;//无法确定调用第1个、还是第2个构造函数?Box

box2(15,30);//无法确定调用第1个、还是第3个构造函数?例2.5.5。拷贝构造函数54拷贝构造函数是一种特殊的构造函数,其形参为本类的对象引用。class

类名{ public

:类名(形参);//构造函数类名(类名&对象名);//拷贝构造函数...};类名::类名(类名&对象名)//拷贝构造函数的实现{

函数体

}构造函数和析构函数例:拷贝构造函数举例55class

Point{public:Point(int

xx=0,int

yy=0){X=xx;

Y=yy;}Point(Point&

p);int

GetX()

{return

X;}int

GetY()

{return

Y;}private:int

X,Y;};构造函数和析构函数Point::Point

(Point&

p){X=p.X;Y=p.Y;cout<<"拷贝构造函数被调用"<<endl;}34例:拷贝构造函数举例57当用类的一个对象去初始化该类的另一个对象时系统自动调用拷贝构造函数实现拷贝赋值。void

main(void){ Point

A(1,2);Point

B(A);//拷贝构造函数被调用

cout<<B.GetX()<<endl;}构造函数和析构函数例:拷贝构造函数举例58若函数的形参为类对象,调用函数时,实参赋值给形参,系统自动调用拷贝

构造函数。例如:void

fun1(Point

p){

cout<<p.GetX()<<endl;}void

main(){ Point

A(1,2);fun1(A);//调用拷贝构造函数}构造函数和析构函数拷贝构造函数59当函数的返回值是类对象时,系统自动调用拷贝构造函数。例如:Point

fun2(){Point

A(1,2);return

A;//调用拷贝构造函数}void

main(){Point

B;B=fun2();}构造函数和析构函数拷贝构造函数60如果程序员没有为类声明拷贝初始化构造函数,则编译器自己生成一个拷贝构造函数。这个构造函数执行的功能是:用作

为初始值的对象的每个数据成员的值,

初始化将要建立的对象的对应数据成员。构造函数和析构函数析构函数61完成对象被删除前的一些清理工作。在对象的生存期结束的时刻系统自动调用它,然后再释放此对象所属的空间。如果程序中未声明析构函数,编译器将自动产生一个默认的析构函数。构造函数和析构函数析构函数62析构函数的作用与构造函数相反。析构函数的特点:析构函数不能接受任何参数,也没有返回类型说明;一个类只有一个析构函数,如果用户未编写析构函数,编译系统会自动生成一个缺省的析构函数,此函数不做任何事情;析构函数不能重载。构造函数和析构函数何时执行析构函数?63一个函数中定义的对象(自动局部的),在这个函数结束调用时,对象应该释放,并在对象释放前自动执行析构函数;static类型的局部对象在函数调用结束时并不释放,也不调用析构函数,只在main函数结束或调用exit函数结束程序时,才调用static局部对象的析构函数;一个全局对象,在程序离开其作用域时(如main函数结束或调用exit函数),调用该全局对象的析构函数;用new运算符动态建立的对象,当用delete运算符释放该对象时,先调用该对象的析构函数;如果用户没定义析构函数,C++编译系统会自动生成一个析构函数,只是它实际上不执行任何操作。例gf9

包含构造函数和析构函数的C++程序。64构造函数和析构函数共同点都没有返回值,无需指出返回类型;不能被继承;构造函数可以有缺省参数;不能用常规调用方法调用构造函数;当

使用完全的限定名(包括对象名、类名、函数名)时可以调用析构函数;定义对象时,编译程序自动调用构造函数,删除对象时,编译程序自动调用析构函数。构造函数和析构函数构造函数和析构函数的调用顺序65调用析构函数的次序正好与调用构造函数的次序相反,最先被调用的构造函数,其对应的(同一对象中的)析构函数最后被调用,而最后被调用的构造函数,其对应的析构函数最先被调用;“先构造的后析构、后构造的先析构”的先进后出的特征。构造函数和析构函数调用构造函数和析构函数的顺序66构造函数和析构函数67指针的基本概念对象指针指针可以指向所有对象指针指向变量--指针变量(存变量的地址)指针指向数组--数组指针(存数组的起始地址)指针指向函数--函数指针(存放函数的入口地址)指针指向指针--指针型指针(存放某指针的地址)由指针组成的数组--指针数组指针指向结构--结构指针指针指向对象—对象指针指针是一种可定位其他对象的特殊类型的数据(存放其他对象的首地址)指针是一种可定位其他对象的特殊类型的数据(存放其他对象的首地址)指向对象的指针68对象存储空间的起始地址叫对象指针;可以定义一个指针变量,存放对象空间的起始地址,如:Time

t1;

//创建Time类对象t1Time

*pt=

&t1

;//定义指向Time类对象//的指针pt,并将t1的起始地址赋给pt对象指针指向对象的指针69可以通过对象指针访问对象和对象的成员,如:*pt(*pt).hour//pt所指向对象t1//pt所指向对象中的hour成员,即t1.

hour//pt所指向对象中的hour成员,pt

->

hour即t1.

hour(*pt).get_time()

//调用pt所指向的对象中的

get_time函数,即t1.

get_timept->get_time()

//调用pt所指向的对象中的

get_time函数,即t1.

get_time对象指针指向对象成员的指针70指向对象数据成员的指针:数据类型名*指针变量名;

p1=&t1.hour;//将对象t1的数据成员hour的地址赋给p1,p1指向t1.

hourcout

<<*p1

<<endl;//输出t1.

hour的值对象指针指向对象成员的指针71指向对象成员函数的指针:1、普通函数:数据类型名(*指针变量名)(参数表列);2、指向公用成员函数的指针变量:数据类型名(类::*指针变量名)(参数表列);3、使指针变量指向一个公用成员函数的一般形式为:指针变量名=&类名::成员函数名;例gf17。对象指针this指针72隐含于每一个类的成员函数中的特殊指针。明确地指出了成员函数当前所操作的数据所属的对象。–当通过一个对象调用成员函数时,系统先将该对象的地址赋给this指针,然后调用成员函数,成员函数对对象的数据成员进行操作时,就隐含使用了this指针。对象指针this指针73例如:Point类的

温馨提示

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

评论

0/150

提交评论