第二章类与对象_第1页
第二章类与对象_第2页
第二章类与对象_第3页
第二章类与对象_第4页
第二章类与对象_第5页
已阅读5页,还剩164页未读 继续免费阅读

下载本文档

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

文档简介

第二章类与对象第一页,共一百八十五页,编辑于2023年,星期四本章主要内容面向对象的思想类概念和声明类的成员构造函数与析构函数用const保护数据友元静态成员this指针第二页,共一百八十五页,编辑于2023年,星期四重点:根据具体问题的算法编写程序,重点考虑本问题的解决方法和流程形式:主模块+若干个子模块(main()+子函数)。每个函数实现一项功能特点:设计者必须考虑每一个细节数据与函数分离,所有数据都是公用的。面向过程设计方法回顾§2.1面向对象程序设计第三页,共一百八十五页,编辑于2023年,星期四缺点:数据与代码分离导致数据改变时需重新编写函数程序功能扩充时程序的可重用性差,效率低。面向过程设计方法回顾§2.1面向对象程序设计主函数函数1函数2函数3函数11函数12函数31函数32数据1数据2数据3第四页,共一百八十五页,编辑于2023年,星期四例:编写小型公司人员信息管理系统某小型公司主要有人员,经理、兼职技术人员、销售经理和兼职推销员。现在需要存储这些人员的姓名、编号、级别、当月薪水、计算月薪总额并显示全部信息。月薪计算方法:经理拿固定月薪8000元兼职技术人员按每小时100元领取月薪兼职推销员月薪按当月销售额的4%提成销售经理既拿固定月薪也领取销售提成,固定月薪为5000元,销售提成为所管辖部门当月销售额的5‰。面向过程设计方法回顾§2.1面向对象程序设计第五页,共一百八十五页,编辑于2023年,星期四分析:一般数据描述用结构体

structemployee

{ char*name;//姓名

intno;//编号

char*job;//职位

floatpaytotal;//月薪总额

floathourlyRate; //每小时酬金

intworkHours; //当月工作时数 floatCommRate; //销售额提取百分比 floatsales; //当月销售额}不同职位月薪计算方法和需要数据个数不同,专用与公用数据混杂,数据结构过于庞大,结构不清面向过程设计方法回顾§2.1面向对象程序设计第六页,共一百八十五页,编辑于2023年,星期四程序结构:函数:employee*input()输入全部数据必须输入全部数据,即使不使用的部分专有数据也不例外,且输入顺序要与数据文件顺序匹配月薪计算函数pay利用函数重载编写各类人员月薪计算函数pay,这样主函数中必须要有相应分支结构,按职位调用相应pay函数voidoutput(employeeperson)输出全部数据除输出公用数据外,其中应有分支结构,根据职位不同输出其专有数据。如:兼职技术人员要输出每小时薪金数及小时数等信息面向过程设计方法回顾§2.1面向对象程序设计第七页,共一百八十五页,编辑于2023年,星期四分析:修改:添加钟点工:4小时以内每小时5元,4小时以上每小时8元。程序修改范围:添加pay函数,修改所有其他函数包括main函数包括数据文件结论:面向过程的程序设计在程序的通用性、扩展性方面存在缺陷。面向过程设计方法回顾§2.1面向对象程序设计第八页,共一百八十五页,编辑于2023年,星期四§2.1面向对象程序设计观点:从程序的通用性入手,将程序潜在使用者作为对象进行全面研究。认为所有问题由彼此相关且能够相互通信的实体(对象)所组成,并总结出对象的共性特点。例:公司:问题。公司中的一个人员:对象。特点:每个对象都有自己的特征(对象的属性)(数据)每个对象都有自己的行为。(操作)例:王经理有自己的编号、月薪等数据属性和自己的行为:月薪计算函数要求:高度概括、分类、和抽象现实问题。将数据与对数据进行的操作封装。面向对象的思想第九页,共一百八十五页,编辑于2023年,星期四抽象:将研究对象(问题)分类并总结出每类对象的公共性质并加以描述将具有相同结构和特性的一批对象总结出来用“类”这种数据结构描述,称为对象的抽象数据抽象:总结出同类对象的基本特点(属性)用物理量(变量等)描述代码抽象:总结出同类对象的共有的行为特征(操作或具有的功能),编写相应专用函数例:编写兼职技术人员的月薪计算函数§2.1面向对象程序设计面向对象的基本特点第十页,共一百八十五页,编辑于2023年,星期四封装:将数据和操作放在一起,视为一个整体称为类,与外界相对分隔。面向对象的基本特点§2.1面向对象程序设计类数据操作代码例:兼职技术人员特有数据:每小时薪金数和月工作时间特有代码:求月薪函数封装成:技术人员类第十一页,共一百八十五页,编辑于2023年,星期四§2.1面向对象程序设计例:兼职技术人员的封装classtechnician:publicemployee

//技术人员类{private: floathourlyRate; //每小时酬金 intworkHours; //当月工作时数public: voidpay()//计算月薪函数 { cin>>workHours; accumPay=hourlyRate*workHours; } };第十二页,共一百八十五页,编辑于2023年,星期四§2.1面向对象程序设计封装特点:数据只能在内部使用,外界及其他类只能通过程序接口联系,可以保护数据使用者不必了解具体的实现细节,只通过外部接口以特定的访问权限,使用类的成员程序扩充功能时可直接编写新的封装模块,设计接口接入程序即可面向对象的基本特点第十三页,共一百八十五页,编辑于2023年,星期四§2.1面向对象程序设计继承与派生:在一个类基础上可派生出新的类新类继承原类的所有成员并可产生新的功能实际操作时通常将所有对象共用的数据及操作作为基础类,不同对象专有数据都从基类中派生得出面向对象的基本特点第十四页,共一百八十五页,编辑于2023年,星期四面向对象的基本特点§2.1面向对象程序设计基类公共数据操作代码经理数据操作代码技术人员数据操作代码销售人员数据操作代码钟点工数据操作代码第十五页,共一百八十五页,编辑于2023年,星期四§2.1面向对象程序设计面向对象程序设计总结:抽象:将对象分类,并总结同类对象的数据属性和相应代码(函数)封装:将同类对象所属数据及函数封装在一个类中派生:类复杂时,将许多类的共同属性及代码用一个公用类(基类)封装,自己类的特有属性及代码用从公用类派生出的派生类封装第十六页,共一百八十五页,编辑于2023年,星期四§2.2类与对象的定义第二章类和对象第十七页,共一百八十五页,编辑于2023年,星期四类是一种用户自定义类型,它是从结构体引申而来:structstudent{ intnum; charname[10]; intscore;};studentstu,stu2;结构体只包括数据,没有操作,结构体成员在本作用域中是“敞开”的,使用不受限制§2.2类与对象的定义类的引入|结构体扩展第十八页,共一百八十五页,编辑于2023年,星期四§2.2类与对象的定义结构体成员在任何函数中均可用直接使用

格式:结构体变量名.成员名voidmain()//no2.2-1.cpp{ studentstu; cin>>stu.num>>>>stu.score; display(stu);}voiddisplay(studentstu){ cout<<stu.num<<<<stu.score<<endl;}类的引入|结构体扩展第十九页,共一百八十五页,编辑于2023年,星期四结构体类型的扩展-在定义中加入代码(函数):structstudent{ intnum; charname[10]; intscore;

voiddisplay() {cout<<"num:"<<num<<endl; cout<<"name:"<<name<<endl; cout<<"score:"<<score<<endl; }};§2.2类与对象的定义数据成员函数成员(代码)扩展的结构体student实现了将数据与对此数据进行的操作封装在一起的功能类的引入|结构体扩展数据是内部成员,直接使用第二十页,共一百八十五页,编辑于2023年,星期四封装后的结构体仍然开放,所有成员均可直接使用,但须按格式使用包括函数成员。voidmain()//no2.2-1A.cpp{ studentstu; cout<<"pleaseinputdata:"; cin>>stu.num>>>>stu.score;

stu.display();}封装后的结构体仍然开放,所有成员均可直接使用§2.2类与对象的定义类的引入|结构体扩展第二十一页,共一百八十五页,编辑于2023年,星期四为保护专有数据兼顾外界使用,设置访问权限,让专有成员只能内部使用,公开成员则任意使用stuctstudent{private: intnum; charname[10]; charsex;

public: voiddisplay() {cout<<"num:"<<num<<endl; cout<<"name:"<<name<<endl; cout<<"sex:"<<sex<<endl; }};§2.2类与对象的定义私有成员,只能内部使用公有成员,外界可以调用类的引入|结构体扩展第二十二页,共一百八十五页,编辑于2023年,星期四设置访问权限后,主函数作为外部,只能使用公有成员。voidmain(){ studentstu; cout<<"pleaseinputdata:"; cin>>

stu.num>>

>>stu.score;

stu.display();}§2.2类与对象的定义类的引入|结构体扩展正确:公有函数可以使用错误:私有成员不可使用第二十三页,共一百八十五页,编辑于2023年,星期四解决方案:绕弯使用,增加公有成员函数间接使用内部成员structstudent{private: intnum; charname[10]; charsex;

public: voidinput()

{ cout<<"pleaseinputdata:"; cin>>num>>name>>score; } voiddisplay() {cout<<"num:"<<num<<endl; cout<<"name:"<<name<<endl; cout<<"sex:"<<sex<<endl; }};类的引入|结构体扩展为外部使用增加的公有函数前一页下一页第二十四页,共一百八十五页,编辑于2023年,星期四主函数通过公有函数input间接使用内部成员voidmain()//no2.2-1B.cpp{ studentstu;

stu.input();

stu.display();}§2.2类与对象的定义类的引入|结构体扩展注意:必须用“变量名.函数名”的格式使用第二十五页,共一百八十五页,编辑于2023年,星期四§2.2类与对象的定义总结:通过扩展结构体数据类型,增加函数成员和访问权限,使结构体实现了面向对象程序设计中的封装为更好进行面向对象程序设计,将扩展的结构体类型改造产生新的数据类型-类类和结构体有着相似的结构,但更为复杂,功能更加扩展,能够实现更加复杂的面向对象的程序设计类的引入|结构体扩展第二十六页,共一百八十五页,编辑于2023年,星期四类的一般声明形式:class类名称{ private:

私有数据和成员函数 protected:

保护型数据和成员函数 public:

公有数据和成员函数

};类的定义§2.2类与对象的定义类关键字成员定义访问权限第二十七页,共一百八十五页,编辑于2023年,星期四§2.2类与对象的定义

例:classABC{

private:

inta;protected:

intb; voidset(intx,inty,intz){a=x;b=y;c=z;}public:

intc; voidprint(){cout<<a<<b<<c<<endl;}};私有成员:变量a保护成员:变量b及函数set公有成员:变量c及函数print类的声明形式第二十八页,共一百八十五页,编辑于2023年,星期四公有权限:在关键字public后面声明,是类与外部的接口,任何外部函数都可以访问。私有权限:在关键字private后面声明,只允许本类中的函数访问,而类外部的任何函数都不能访问。如果紧跟在类名称的后面声明私有成员,则关键字private可以省略。类的访问权限§2.2类与对象的定义第二十九页,共一百八十五页,编辑于2023年,星期四在关键字protected后面声明,与private类似,其差别表现在继承与派生时对派生类的影响不同。§2.2类与对象的定义类的访问权限第三十页,共一百八十五页,编辑于2023年,星期四classABC{

inta;protected:

intb;public:

intc; voidset(intx,inty,intz){a=x;b=y;c=z;} voidprint(){cout<<"a="<<a<<'\n'<<"b="<<b

<<'\n'<<"c="<<c<<endl;}};注意:内部函数可以使用全部数据成员而外部(如主函数中)只能使用公有数据成员c及公有函数成员set和print且必须通过对象使用不同权限的成员例前一页下一页休息休息默认权限为private第三十一页,共一百八十五页,编辑于2023年,星期四§2.2类与对象的定义类的对象是该类的某一特定实体,即类类型的变量定义形式:

存储类型

类名

对象名;举例:

ABC

d1;定义的三种方式:先定义类,后定义对象;定义类的同时,定义对象;无类名,直接定义对象对象的定义第三十二页,共一百八十五页,编辑于2023年,星期四§2.2类与对象的定义对象与结构体变量一样,一般不能整体使用,只能使用成员一般格式:

对象名.成员名上例:如已有定义:ABCd1;则:

d1.c=28;d1.set(1,2,3);都是正确的对象使用对象的使用定义第三十三页,共一百八十五页,编辑于2023年,星期四§2.2类与对象的定义对象的位置在类外,因此不是所有类的成员都能通过对象使用,它受到访问权限的限制。只有public属性的成员可以通过对象在类外使用例:cout<<d1.c<<endl;

cout<<d1.a<<d1.b<<endl;╳对象的使用定义第三十四页,共一百八十五页,编辑于2023年,星期四§2.2类与对象的定义提醒:类中的成员函数要使用数据成员时不受访问权限的限制使用方法:直接使用成员名例:ABC类的成员函数set中:

a=x;b=y;c=z;其中a、b是禁止外界使用的私有和保护成员,而c是任意使用的公有成员对象的使用定义第三十五页,共一百八十五页,编辑于2023年,星期四例:不同类型成员的使用classABC{

inta;protected:

intb;public:

intc; voidset(intx,inty,intz){a=x;b=y;c=z;} voidprint(){cout<<"a="<<a<<'\n'<<"b="<<b

<<'\n'<<"c="<<c<<endl;}};类中成员的访问实例前一页下一页休息休息类中访问直接用成员名且不受权限限制第三十六页,共一百八十五页,编辑于2023年,星期四voidmain()//no2.2-2.cpp{ intx,y,z; ABCabc;abc.c=10;//类外访问:公有成员直接引用abc.a=5;abc.b=8;

//私有及保护成员不能直接引用//私有及保护成员只能通过公有成员函数引用 cout<<"pleaseinputdata:"; cin>>x>>y>>z;

abc.set(x,y,z);

abc.print();}类中成员的访问方式前一页休息休息下一页第三十七页,共一百八十五页,编辑于2023年,星期四例:类外通过公有成员函数使用私有和保护成员classABC{

inta;protected:

intb;public:

intc; voidset(intx,inty,intz){a=x;b=y;c=z;} intgeta(){returna;} intgetb(){returnb;} voidprint(){cout<<"a="<<a<<'\n'<<"b="<<b

<<'\n'<<"c="<<c<<endl;}};类中成员的访问方式前一页下一页休息休息第三十八页,共一百八十五页,编辑于2023年,星期四voidmain(){ intx,y,z,d; ABCabc;

abc.c=10;//公有成员直接引用 cout<<"c="<<abc.c<<endl; cout<<"pleaseinputdata:"; cin>>x>>y>>z;

abc.set(x,y,z);

//私有及保护成员只能通过公有成员函数引用abc.print(); d=abc.geta()+abc.getb()+abc.c; cout<<"d="<<d<<endl;}类中成员的访问方式前一页休息休息下一页第三十九页,共一百八十五页,编辑于2023年,星期四成员函数:成员函数可是带缺省形参值的函数。成员函数可以重载成员函数较长时可写在类定义外面

此时函数首行形式为:

函数类型类名::函数名(形参表)成员函数的特殊性成员函数的变化实例1实例2实例3第四十页,共一百八十五页,编辑于2023年,星期四#include<iostream.h>//no2.2-3.cppclassPoint

//Point类通常表示平面坐标上的点{public: voidSet(intxx=0,intyy=0) { X=xx;Y=yy; } intGetX(){returnX;}//为外界取X值 intGetY(){returnY;}//为外界取Y值private: intX,Y;};下一页前一页休息休息第四十一页,共一百八十五页,编辑于2023年,星期四voidmain(){ Pointp; //定义Point类的对象 p.Set(10,4); cout<<"NO1:x="<<p.GetX(); cout<<"y="<<p.GetY()<<endl; p.Set(); cout<<"NO2:x="<<p.GetX(); cout<<"y="<<p.GetY()<<endl;}执行结果:NO1:x=10y=4NO2:x=0y=0下一页前一页休息休息返回第四十二页,共一百八十五页,编辑于2023年,星期四#include<iostream.h>//no2.2-3A.cppclassPoint

//Point类通常表示平面坐标上的点{public: voidSet()//无参Set函数 { X=0;Y=0;} voidSet(intxx,intyy)//重载有参Set函数 { X=xx;Y=yy;} intGetX(){returnX;}//为外界取X值 intGetY(){returnY;}//为外界取Y值private: intX,Y;};下一页前一页休息休息第四十三页,共一百八十五页,编辑于2023年,星期四voidmain(){ Pointp; //定义Point类的对象 p.Set(10,4); cout<<"NO1:x="<<p.GetX(); cout<<"y="<<p.GetY()<<endl; p.Set(); cout<<"NO2:x="<<p.GetX(); cout<<"y="<<p.GetY()<<endl;}执行结果:NO1:x=10y=4NO2:x=0y=0下一页前一页休息休息返回第四十四页,共一百八十五页,编辑于2023年,星期四classstudent

//no2.2-4.cpp{intnum; charname[10]; charsex;

public:

voiddisplay(intn,charnam[],chars);};void

student::display(intn,charnam[],chars){ num=n;sex=s; strcpy(name,nam); cout<<"num:"<<num<<endl;cout<<"name:"<<name<<endl;cout<<"sex:"<<sex<<endl; }休息休息下一页前一页第四十五页,共一百八十五页,编辑于2023年,星期四voidmain(){ studstud1; stud1.display(21001,"林华",'w');}执行结果:num:21001name:林华sex:w下一页休息休息前一页返回第四十六页,共一百八十五页,编辑于2023年,星期四函数体在类的声明中定义实际上是一种内联成员函数。为了提高运行时的效率,对于较简单的函数可以声明为内联形式。内联函数体中不要有复杂结构(如循环语句和switch语句)。还可使用inline关键字在函数外定义内联成员函数。成员函数的特殊性内联成员函数第四十七页,共一百八十五页,编辑于2023年,星期四classPoint//点类用于描述一个点的坐标{public:voidInit(intinitX,intinitY);intGetX(),GetY();private:intX,Y;};inlinevoidPoint::Init(intinitX,intinitY){X=initX;Y=initY;}inlineintPoint::GetX(){returnX;}inlineintPoint::GetY(){returnY;}前一页下一页休息休息成员函数的特殊性第四十八页,共一百八十五页,编辑于2023年,星期四intmain()//no2.2-5.cpp{ PointA; A.Init(1,2); cout<<A.GetX()<<'\t'<<A.GetY()<<endl; return0;}§2.2类与对象的定义成员函数的特殊性第四十九页,共一百八十五页,编辑于2023年,星期四形式上:类与结构体类同。相同:都可以有成员,都可以使用限定访问权限的关键字(private,public和protected),引用的形式相同。区别:类中缺省的访问权限是私有的,而在结构体中缺省的访问权限是公有的。可以认为结构体是类的一个特例。类的其他性质§2.2类与对象的定义第五十页,共一百八十五页,编辑于2023年,星期四类的应用举例一圆型游泳池如图所示,现在需在其周围建一圆型过道,并在其四周围上栅栏。栅栏价格为35元/米,过道造价为20元/平方米。过道宽度为3米,游泳池半径由键盘输入。要求编程计算并输出过道和栅栏的造价。游泳池过道第五十一页,共一百八十五页,编辑于2023年,星期四类的应用举例分析:算法:栅栏造价=单价×大圆周长过道造价=单价×(大圆面积–小圆面积)数据结构:反复进行圆计算,考虑定义圆类Cirle数据成员:小圆半径:floatradius;

大圆半径比小圆固定大3,直接运算

造价和单价与圆无关不编入圆类函数成员voidInit(floatr):为半径赋值floatCircumference():求圆周长floatArea():求圆面积第五十二页,共一百八十五页,编辑于2023年,星期四#include<iostream.h>//no2.2-6.cppconstfloatPI=3.14159;constfloatFencePrice=35;constfloatConcretePrice=20;//声明类Circle及其数据和方法classCircle{private:floatradius;

public:voidInit(floatr);//赋值函数floatCircumference();//圆周长floatArea();//圆面积};下一页前一页休息休息第五十三页,共一百八十五页,编辑于2023年,星期四//类的实现//为数据成员radius赋值voidCircle::Init(floatr){radius=r;}//计算圆的周长floatCircle::Circumference(){return2*PI*radius;}

//计算圆的面积

floatCircle::Area(){returnPI*radius*radius;}下一页前一页休息休息第五十四页,共一百八十五页,编辑于2023年,星期四voidmain(){ floatradius; floatFenceCost,ConcreteCost;

//提示用户输入半径 cout<<"Entertheradiusofthepool:"; cin>>radius;

//声明Circle对象并赋值 CirclePool,PoolRim; Pool.Init(radius); PoolRim.Init(radius+3);前一页下一页休息休息第五十五页,共一百八十五页,编辑于2023年,星期四//计算栅栏造价并输出FenceCost=PoolRim.Circumference()*FencePrice;cout<<"FencingCostis¥"<<FenceCost<<endl;

//计算过道造价并输出ConcreteCost=(PoolRim.Area()-Pool.Area())*ConcretePrice;cout<<"ConcreteCostis¥"<<ConcreteCost<<endl;}运行结果Entertheradiusofthepool:10FencingCostis¥2858.85ConcreteCostis¥4335.39前一页下一页休息休息第五十六页,共一百八十五页,编辑于2023年,星期四§2.3组合类第二章类和对象的定义第五十七页,共一百八十五页,编辑于2023年,星期四§2.3组合类类中的成员数据是另一个类的对象时称此类为组合类必须用已有对象为组合类中的对象成员赋值使用对象成员时因其在类外,要受访问权限控制类的组合概念第五十八页,共一百八十五页,编辑于2023年,星期四§2.3组合类classPoint //普通类{public: voidInit(intxx=0,intyy=0)//设置函数 { X=xx;Y=yy; } intGetX(){returnX;}//取X的值 intGetY(){returnY;}//取Y的值private: intX,Y;};类的组合举例第五十九页,共一百八十五页,编辑于2023年,星期四classDistance//组合类

{public:

voidSet(Pointxp1,Pointxp2);//设置函数 doubleGetDis();//求距离private:

Pointp1,p2; //Point类对象,两端点坐标 doubledist; //两点间距离};下一页前一页休息休息形参是其他类对象第六十页,共一百八十五页,编辑于2023年,星期四voidDistance::Set(Pointxp1,Pointxp2){ p1=xp1;//同类对象可直接赋值 p2=xp2;//形参对象赋值给成员对象} doubleDistance::GetDis(){ doublex,y; x=double(p1.GetX()-p2.GetX()); y=double(p1.GetY()-p2.GetY());

dist=sqrt(x*x+y*y); returndist;}下一页前一页休息休息现在位置是Point类外,须通过对象名使用成员,且只能使用公有成员函数本类成员直接使用第六十一页,共一百八十五页,编辑于2023年,星期四voidmain()//no2.3-1.cpp{

Pointmyp1,myp2; myp1.Init(1,1);myp2.Init(4,5);

//为Point类对象赋值

Distancemyd; myd.Set(myp1,myp2);//为Distance类对象赋值 cout<<"Thedistanceis:"; cout<<myd.GetDis()<<endl;}下一页前一页休息休息结果为:Thedistanceis:5第六十二页,共一百八十五页,编辑于2023年,星期四§2.3组合类类应该先定义,后使用上例:如Point类定义在Distance类之后,程序将出错如果需要在某个类的定义之前,引用该类,则应进行前向引用声明声明格式:

class类名;前向引用声明只为程序引入一个标识符,但类具体定义在其它地方前向引用声明第六十三页,共一百八十五页,编辑于2023年,星期四§2.3组合类classB;//前向引用声明classA{public:voidf(Bb);//引用B类对象};classB{public:voidg(Aa);//引用A类对象};前向引用声明举例第六十四页,共一百八十五页,编辑于2023年,星期四§2.4构造函数第二章类和对象的定义第六十五页,共一百八十五页,编辑于2023年,星期四§2.4构造函数构造函数是一种特殊的类成员函数构造函数的作用初始化对象中的数据成员特点:构造函数名必须与类名相同。构造函数无返回值且不必用类型名void构造函数概念第六十六页,共一百八十五页,编辑于2023年,星期四构造函数举例#include<iostream.h>//no2.4-1.cppclassPoint{public: Point(inta,intb)//构造函数,给对象赋初值

{X=a;Y=b;} voidInit(intinitX,intinitY)

//赋值函数,修改对象值{X=initX;Y=initY;} intGetX(){returnX;}//取X值函数 intGetY(){returnY;}//取Y值函数private:intX,Y;};构造函数举例函数名与类名相同且无类型名第六十七页,共一百八十五页,编辑于2023年,星期四§2.4构造函数对象定义另一格式:

类名对象名(实参表)例:PointP1(1,2)

定义对象P1,且为其两个数据成员X、Y分别赋初值1和2构造函数的调用方法:创建对象时用户给定实参,由系统自动调用构造函数的调用第六十八页,共一百八十五页,编辑于2023年,星期四构造函数举例intmain(){

PointA(1,2);

//定义对象A,同时系统自动调用构造函数为A赋初值 cout<<A.GetX()<<'\t'<<A.GetY()<<endl; return0;}构造函数举例执行结果:12第六十九页,共一百八十五页,编辑于2023年,星期四§2.4构造函数构造函数可以有参亦可无参上例:如X、Y默认初值为0,则构造函数可为: Point(){X=Y=0;}对应对象定义:

PointA注意:不可带实参,也不必带括号构造函数特性第七十页,共一百八十五页,编辑于2023年,星期四§2.4构造函数程序可不定义构造函数,此时系统自动产生一个默认的构造函数,为无参空函数。上例,系统自动定义的构造函数为:

Point(){}构造函数允许为内联函数、重载函数、带默认形参值的函数。构造函数特性第七十一页,共一百八十五页,编辑于2023年,星期四实例:定义一个时间类,并测试//no2.4-2.cppclassTime{public:

Time();//重载构造函数 Time(intNewH,intNewM,intNewS); voidSetTime(intNewH,intNewM,intNewS);//设置时间 voidShowTime();//显示时间private: intHour,Minute,Second;};重载构造函数举例§2.4构造函数第七十二页,共一百八十五页,编辑于2023年,星期四//构造函数的实现:Time::Time(){ Hour=0;Minute=0;Second=0;}Time::Time(intNewH,intNewM,intNewS){ Hour=NewH;Minute=NewM; Second=NewS;}Time::voidSetTime(intNewH,intNewM,intNewS){Hour=NewH;Minute=NewM;Second=NewS;}Time::voidShowTime(){cout<<Hour<<":"<<Minute<<":"<<Second<<endl;}休息前一页下一页第七十三页,共一百八十五页,编辑于2023年,星期四//建立对象时构造函数的作用:voidmain(){

Timeb;//调用无参构造函数

Timec(12,30,0);//调用构造函数,将初始值作为实参b.ShowTime(); c.ShowTime();}结果为:0:0:012:30:0休息前一页下一页第七十四页,共一百八十五页,编辑于2023年,星期四§2.4构造函数构造函数的另一种形式构造函数还可用在函数外直接为其成员初始化的方法为成员赋初值成员初始化格式:

成员名1(形参1),成员名2(形参2)……构造函数另一格式:

类名(形参表):

成员初始化

{}例:上例Time类无参构造函数可写为:

Time():Hour(0),Minute(0),Second(0){}构造函数特性第七十五页,共一百八十五页,编辑于2023年,星期四实例:定义时间类,并测试//no2.4-2A.cppclassTime{public: Time(intNewH=0,intNewM=0,intNewS=0); voidSetTime(intNewH,intNewM,intNewS);//设置时间 voidShowTime();//显示时间private: intHour,Minute,Second;};带默认值构造函数举例§2.4构造函数第七十六页,共一百八十五页,编辑于2023年,星期四//构造函数的实现:Time::Time(intNewH,intNewM,intNewS){ Hour=NewH;Minute=NewM;Second=NewS;}Time::voidSetTime(intNewH,intNewM,intNewS){Hour=NewH;Minute=NewM;Second=NewS;}Time::voidShowTime(){cout<<Hour<<":"<<Minute<<":"<<Second<<endl;}休息前一页下一页第七十七页,共一百八十五页,编辑于2023年,星期四//建立对象时构造函数的作用:voidmain(){

Timeb;//构造函数中使用默认值

Timec(12,30,0);//构造函数中使用形参初始化b.ShowTime(); c.ShowTime();}结果为:0:0:012:30:0休息前一页下一页第七十八页,共一百八十五页,编辑于2023年,星期四classsample//no2.4-3.cpp{ inti;

public: sample(){i=0;}

sample(intx=1){i=x;} voiddisplay(){cout<<i<<endl;}};voidmain(){ sampleB(5),A; A.display(); B.display();}构造函数的二义性会引起二义性§2.4构造函数第七十九页,共一百八十五页,编辑于2023年,星期四§2.4构造函数二义性解决方法删除无参构造函数重载定义一个无参构造函数和一个不带默认值的构造函数如上例定义成:sample(){i=0;}sample(intx){i=x;}注意:有时将无参或带默认值的构造函数亦称为默认构造函数第八十页,共一百八十五页,编辑于2023年,星期四§2.5析构函数第二章类和对象的定义第八十一页,共一百八十五页,编辑于2023年,星期四§2.5析构函数析构函数亦为特殊的成员函数函数格式:~类名()

{函数体}特点:无返回值,亦不必写void无参,亦不可进行重载功能:完成对象被删除前的一些清理工作析构函数概念第八十二页,共一百八十五页,编辑于2023年,星期四§2.5析构函数#include<iostream.h>//no2.5-1.cppclassPoint{public:Point(intinitX,intinitY); ~Point(); intGetX(){returnX;} intGetY(){returnY;}private:intX,Y;};析构函数举例第八十三页,共一百八十五页,编辑于2023年,星期四§2.5析构函数Point::Point(intinitX=0,intinitY=0){ X=initX;Y=initY; cout<<"调用了构造函数"<<endl;}Point::~Point()

{ cout<<"调用了析构函数\n"; }析构函数举例第八十四页,共一百八十五页,编辑于2023年,星期四§2.5析构函数intmain(){

PointA(1,2); cout<<A.GetX()<<'\t'<<A.GetY()<<endl; return0;}析构函数举例执行结果:调用了构造函数12调用了析构函数第八十五页,共一百八十五页,编辑于2023年,星期四§2.5析构函数析构调用方式:在对象的生存期结束的时刻由系统自动调用,然后再释放此对象所属的空间析构函数是对象生命结束前最后一个执行的函数如果程序中未声明析构函数,编译器将自动产生一个缺省的空析构函数当成员函数中有动态创建内存操作时,必须定义析构函数在对象生命结束前释放空间析构函数特点第八十六页,共一百八十五页,编辑于2023年,星期四必须编写析构函数实例(no2.5-2.cpp

)#include<iostream.h>#include<iomanip.h>classArray {public: Array(floatdata[],intn1); voidprocess(); voidshow(); ~Array();private: intn; float*a; floataverage;};析构函数举例成员为指针,准备进行动态内存分配前一页下一页第八十七页,共一百八十五页,编辑于2023年,星期四§2.5析构函数Array::Array(floatdata[],intn1)//构造函数{ n=n1;

a=newfloat[n]; for(inti=0;i<n;i++)a[i]=data[i];}Array::~Array()//析构函数{

delete[]a;}析构函数举例动态开辟了内存并用成员a存放其地址必须在对象结束前释放动态内存第八十八页,共一百八十五页,编辑于2023年,星期四§2.5析构函数voidArray::process()//求数组平均值函数{ average=0.0; for(inti=1;i<n;i++) average+=a[i]; average/=n;}voidArray::show()//输出函数{ cout<<"数组元素:"<<endl; for(inti=0;i<n;i++) { cout<<setw(4)<<a[i]; if((i+1)%5==0)cout<<endl; } cout<<"数组元素平均值为:"<<average<<endl;}析构函数举例第八十九页,共一百八十五页,编辑于2023年,星期四§2.5析构函数voidmain() { Arrayv(data,n1);//定义对象并调用构造函数初始化 intn1,i; floatdata[20];//普通数组大小必须为常量 cout<<"请输入数组元素个数:"<<endl; cin>>n1; cout<<"请输入数组:"<<endl; for(i=0;i<n1;i++) cin>>data[i]; cess(); v.show();}析构函数举例第九十页,共一百八十五页,编辑于2023年,星期四§2.6复制构造函数第二章类和对象的定义第九十一页,共一百八十五页,编辑于2023年,星期四§2.6复制构造函数复制构造函数又称拷贝构造函数是一种特殊的构造函数,其形参为本类的对象引用。class类名{public:类名(形参);//构造函数类名(类名&对象名);//复制构造函数...};类名::类名(类名&对象名)//复制构造函数的实现{函数体}复制构造函数第九十二页,共一百八十五页,编辑于2023年,星期四§2.6复制构造函数classPoint//no2.6-1.cpp{public:Point(intxx=0,intyy=0);//构造函数 Point(Point&p);//复制构造函数intGetX(){returnX;}intGetY(){returnY;}private:intX,Y;};复制构造函数举例第九十三页,共一百八十五页,编辑于2023年,星期四Point::Point(intxx=0,intyy=0)//构造函数实现{ //直接为本对象成员赋值 X=xx;Y=yy; cout<<"构造函数被调用"<<endl;}Point::Point(Point&p)//复制构造函数{

//用形参对象的成员值为本对象成员赋值X=p.X;Y=p.Y;cout<<"复制构造函数被调用"<<endl;}下一页休息休息前一页第九十四页,共一百八十五页,编辑于2023年,星期四复制构造函数的调用定义对象时到底调用构造函数还是复制构造函数由系统根据情况决定一般以下三种情况下系统自动调复制构造函数用对象初始化另一对象形参是对象时对象型函数复制构造函数第九十五页,共一百八十五页,编辑于2023年,星期四复制构造函数的调用当用类的一个对象去初始化该类的另一个对象时系统自动调用它实现拷贝赋值。 voidmain(void){PointA(1,2);//构造函数被调用PointB(A);

//复制构造函数被调用cout<<"A:x="<<A.GetX()<<"A:y="<<A.GetY()<<endl;cout<<"B:x="<<B.GetX()<<"B:y="<<B.GetY()<<endl;}复制构造函数第九十六页,共一百八十五页,编辑于2023年,星期四复制构造函数的调用若函数的形参为对象,调用函数时,实参要给形参传值,需要系统自动调用复制构造函数。例如:voidfun1(Pointp)//no2.6-1A.cpp{cout<<p.GetX()<<endl;}voidmain(){PointA(1,2);fun1(A);//对象A作实参与形参对象p虚实结合时调用复制构造函数}复制构造函数第九十七页,共一百八十五页,编辑于2023年,星期四复制构造函数的调用当函数的返回值是对象时,由于函数内部对象即将失去存储空间,故系统定义一个临时无名对象以记下要返回的值,并自动调用复制构造函数为此对象赋初值。例如:Pointfun2()//no2.6-1B.cpp{PointA(1,2);returnA;//调用复制构造函数}voidmain(){PointB;B=fun2();}复制构造函数第九十八页,共一百八十五页,编辑于2023年,星期四§2.6复制构造函数如果程序没有编写复制构造函数,编译器将自动生成默认复制构造函数。默认复制构造函数的功能:用作为初始值的对象的每个数据成员的值,初始化将要建立的对象的对应数据成员复制构造函数的特点第九十九页,共一百八十五页,编辑于2023年,星期四§2.7组合类的构造函数第二章类和对象的定义第一百页,共一百八十五页,编辑于2023年,星期四§2.7组合类的构造函数原则:不仅要对本类中的基本类型成员数据赋初值,也要对对象成员初始化声明形式:类名::类名(对象成员所需的形参,本类成员形参)

:对象1(参数),对象2(参数),......{本类初始化}类组合的构造函数第一百零一页,共一百八十五页,编辑于2023年,星期四classPoint {public: Point(intxx=0,intyy=0) { X=xx;Y=yy; } Point(Point&p);//函数实现略 intGetX(){returnX;} intGetY(){returnY;}private: intX,Y;};组合类的构造函数类的组合举例第一百零二页,共一百八十五页,编辑于2023年,星期四classDistance//类的组合

{public: Distance(Pointxp1,Pointxp2); doubleGetDis(){returndist;}private:

Pointp1,p2; //Point类的对象p1,p2 doubledist; };组合类的构造函数第一百零三页,共一百八十五页,编辑于2023年,星期四Distance::Distance(Pointxp1,Pointxp2):p1(xp1),p2(xp2)//对对象成员进行初始化{ doublex,y;cout<<"Distance构造函数被调用"<<endl; x=p1.GetX()-p2.GetX(); y=p1.GetY()-p2.GetY();

dist=sqrt(x*x+y*y);}组合类的构造函数第一百零四页,共一百八十五页,编辑于2023年,星期四voidmain()//no2.7-1.cpp{

Pointmyp1(1,1),myp2(4,5);

Distancemyd(myp1,myp2); cout<<"Thedistanceis:"; cout<<myd.GetDis()<<endl;}//本函数共定义了三个对象组合类的构造函数第一百零五页,共一百八十五页,编辑于2023年,星期四结果为:Point构造函数被调用Point构造函数被调用Point拷贝构造函数被调用Point拷贝构造函数被调用Point拷贝构造函数被调用Point拷贝构造函数被调用Distance构造函数被调用Thedistanceis:5下一页前一页休息休息第一百零六页,共一百八十五页,编辑于2023年,星期四组合类的构造函数构造函数调用顺序:先调用内嵌对象的构造函数(按内嵌时的声明顺序,先声明者先构造)。然后调用本类的构造函数。若调用缺省构造函数(即无形参的),则内嵌对象的初始化也将调用相应的缺省构造函数。析构函数也是同样处理,只是调用顺序正好相反类组合的构造函数第一百零七页,共一百八十五页,编辑于2023年,星期四结果分析:Point构造函数被调用//Point类对象myp1初始化Point构造函数被调用//Point类对象myp2初始化Point拷贝构造函数被调用//虚实结合Point拷贝构造函数被调用//虚实结合Point拷贝构造函数被调用//构造函数中用xp1初始化p1Point拷贝构造函数被调用//构造函数中用xp2初始化p2Distance构造函数被调用Thedistanceis:5下一页前一页休息休息第一百零八页,共一百八十五页,编辑于2023年,星期四加析构函数的结果为://no2.7-1A.cppPoint构造函数被调用Point构造函数被调用Point拷贝构造函数被调用Point拷贝构造函数被调用Point拷贝构造函数被调用Point拷贝构造函数被调用Distance构造函数被调用Thedistanceis:5Distance析构函数被调用//撤消Distance类对象mydPoint析构函数被调用//撤消Distance类对象成员p1Point析构函数被调用//撤消Distance类对象成员p2Point析构函数被调用//撤消Point类对象myp1Point析构函数被调用//撤消Point类对象myp2下一页前一页休息休息第一百零九页,共一百八十五页,编辑于2023年,星期四§2.8用const保护数据第二章类和对象的定义第一百一十页,共一百八十五页,编辑于2023年,星期四用const保护数据为确保数据能在一定范围内共享,又不被任意修改,C++允许使用const关键字来修饰有关数据定义,使这些数据在本程序中作常量处理,不能改变其值使用const的常见情况常对象成员常对象常引用第一百一十一页,共一百八十五页,编辑于2023年,星期四常对象成员常对象成员定义类时在部分成员定义中加入关键字const,此成员即成为常对象成员分类:常数据成员常成员函数用const保护数据第一百一十二页,共一百八十五页,编辑于2023年,星期四常数据成员常数据成员定义格式:

const类型名数据成员名特点:不能在程序中改变常数据成员的值常数据成员只能通过构造函数的参数初始化表进行初始化用const保护数据第一百一十三页,共一百八十五页,编辑于2023年,星期四常数据成员使用实例classCircle{private: doubleradius; //半径

constdoublePI; //圆周率,常数据成员public: Circle(doubler)

:PI(3.1415926)

//构造函数 {radius=r;} voidSetRadius(doubler){radius=r;}//设置半径 voidShow() //输出信息 { cout<<"半径:"<<radius<<"\t"; cout<<"面积:"<<PI*radius*radius<<endl; }};用const保护数据常数据成员不通过形参赋值参数初始化为常数据成员赋初值第一百一十四页,共一百八十五页,编辑于2023年,星期四常数据成员使用实例intmain() //no2.8-1.cpp

{ Circlec(1); //定义半径为1的圆 c.Show(); c.SetRadius(2);//设置圆半径为2 c.Show(); system("PAUSE"); return0;}用const保护数据运行结果:半径:1面积:3.14159半径:2面积:12.5664请按任意键继续...

第一百一十五页,共一百八十五页,编辑于2023年,星期四常成员函数定义格式:类型名函数名(形参表)const特点:只能引用本类中的所有数据成员,但不能修改它们函数声明和函数定义处都要加const关键字,调用时不加用const保护数据第一百一十六页,共一百八十五页,编辑于2023年,星期四classCircle{private: doubleradius; //半径

constdoublePI; //圆周率,常数据成员public: Circle(doubler)

:PI(3.1415926

)//构造函数 {radius=r;} voidSetRadius(doubler)//设置半径 {radius=r;}

doubleGetArea()

const

//返回面积常成员函数 {returnPI*radius*radius;}

voidShow()const; //输出信息常成员函数};常成员函数使用实例前一页下一页第一百一十七页,共一百八十五页,编辑于2023年,星期四voidCircle::Show()const//输出信息常成员函数{ cout<<"半径:"<<radius<<"\t"; cout<<"面积:"<<GetArea()<<endl;}intmain() //no2.8-1A.cpp

{ Circlec(1); //定义半径为

温馨提示

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

评论

0/150

提交评论