第四章类和对象本章重点内容:1、c++中定义类的方法2、对象的建立和使用方法3、构造函数和析构函数4.1类及其实例化一、定义类(1、声明类)类是一种用户自定义的数据类型,是对一组性质相同的对象的程序描述。和其他数据类型不同的是,组成这种类型的不仅可以有数据,而且可以有对数据进行操作的函数,它们分别叫做和。数据成员成员函数类的声明以关键字开始。其声明的一般形式:classclass类名{数据成员和成员函数};private:私有数据和函数public:公有数据和函数protected:保护数据和函数访问权限:私有的公有的保护的privatepublicprotected类体分号作为类声明语句的结束标志。注:如果没有使用关键字,则所有成员默认声明为权限。private类的一般定义形式:class类名{private:私有数据和函数public:公有数据和函数protected:保护数据和函数};注:(1)对于数据成员可以像声明变量一样来声明它。(3)成员函数可以访问类中的任何成员(包括数据成员和成员函数),而无需将其声明为参数,惟一的限制条件是在使用一个成员之前必须声明它。(2)对于成员函数,一般是使用函数原型来声明它,而把函数的具体实现在类外来定义(尤其是对于函数体语句比较多的成员函数)。例题:根据下图定义一个描述点的类PointPointx:floaty:floatDisplay:voidSetxy:voidGetx:floatGety:floatclassPoint{}floatx,y;voiddisplay();public:voidSetxy(floata,floatb);floatGetx();floatGety();;2、定义成员函数类中声明的成员函数用来对数据成员进行操作,还必须在程序中实现这些成员函数。classPoint{floatx,y;public:voiddisplay();voidSetxy(floata,floatb);floatGetx();floatGety();};定义成员函数的一般形式:返回类型类名::成员函数名(参数列表){函数体}“::”是作用域运算符,表明其后的成员函数属于某个特定的类。例题:定义Point类的成员函数classPoint{floatx,y;public:voidDisplay();voidSetxy(floata,floatb);floatGetx();floatGety();};显示坐标x和y的值voidPoint::display(){cout(x,y)endl;}voidPoint::Setxy(floata,floatb){x=a;y=b;}floatPoint::Gety(){returny;}floatPoint::Getx(){returnx;}设置坐标x和y的值设置坐标x和y的值分别返回坐标x和y的值也可以使用关键字将成员函数说明为内联函数。inlineinlinevoidPoint::display()classPoint{floatx,y;public:voidDisplay();voidSetxy(floata,floatb);floatGetx();floatGety();};voidPoint::Display(){cout(x,y)endl;}voidPoint::Setxy(floata,floatb){x=a;y=b;}floatPoint::Getx(){returnx;}floatPoint::Gety(){returny;}注:(1)对于简单的成员函数也可以直接在类体内给出定义。{returnx;}{returny;}(2)在类体内定义的成员函数,默认为内联函数。3、数据成员的赋值类是一种数据类型,系统不会给类分配存储空间,所以在定义一个类的时候,不能在类体内给数据成员赋值。例如:下面的方法是错误的:classPoint{floatx=2.5,y=6.9;public:…………};错误:不能在类体内给数据成员赋值只有在定义了类的对象后,才能给对象的数据成员赋值。如果在产生对象时就使对象的数据成员具有指定值,称为对象的初始化。(通过来实现)也可以在定义了对象之后,通过调用成员函数给数据成员赋值。(通过来实现)构造函数成员函数二、对象的定义一旦声明了一个类,就可以用它作为数据类型来定义类的对象(简称为对象)。定义对象的格式:类型对象名表可以是一般的对象名,指针变量名(即对象指针)引用名(即对象引用)对象数组名如:Pointa;Point*pa;Point&ra=a;Pointb[5];以上都是的定义正确形式。三、使用类的对象定义了类的对象之后,就可以使用对象的数据成员和成员函数了。对象和引用都是用运算符“.”访问对象成员,指针则使用“-”运算符。对象的数据成员访问方式:对象名.数据成员名或者引用名.数据成员名或者对象指针名-数据成员名对象的成员函数访问方式:对象名.成员函数名(参数列表)或者引用名.成员函数名(参数列表)或者对象指针名-成员函数名(参数列表)请仔细阅读课本:P72(1)(2)(3)(4)及表4.1例题:classPoint{floatx,y;public:voidDisplay();voidSetxy(floata,floatb);floatGetx();floatGety();};voidPoint::Display(){coutx,yendl;}voidPoint::Setxy(floata,floatb){x=a;y=b;}floatPoint::Getx(){returnx;}floatPoint::Gety(){returny;}voidmain(){Pointa;a.Setxy(3.5,5.8);a.Display();Point&ra=a;coutra.Getx(),ra.Gety()endl;Point*pa=&a;pa-Setxy(3.6,9.3);pa-Display();}练习:分析以下程序结果(lt4_3.cpp)#includeiostreamusingnamespacestd;classPoint{intx,y;public:voidSetxy(inta,intb){x=a;y=b;}voidMove(inta,intb){x=x+a;y=y+b;}voidDisplay(){coutx,yendl;}intGetx(){returnx;}intGety(){returny;}};voidprint(Point*a){a-Display();}voidprint(Point&a){a.Display();}voidmain(){Pointa,b,*p;Point&ra=a;a.Setxy(25,55);b=a;//同类的对象可以相互赋值p=&b;p-Setxy(112,115);print(p);p-Display();ra.Move(-80,23);print(a);print(&a);}四、数据封装C++通过类实现封装,即通过指定个成员的访问权限来实现。访问权限:private、public、protected所谓封装就是:通过对象可以在类外使用公有成员,通过对象不可以在类外使用私有成员,在类内可以直接使用所有成员成员函数是对象具有的功能,我们说对象间利用公有成员函数进行通信。公用成员函数是对象的接口。4.2构造函数(重点掌握)在刚定义类对象时,其数据成员有时需要有初始值。但在类声明体中不能在声明时初始化数据成员,私有的数据成员也不能从类以外来访问。怎么办?classPoint{intx,y;public:voidSetxy(inta,intb){x=a;y=b;}voidMove(inta,intb){x=x+a;y=y+b;}voidDisplay(){coutx,yendl;}intGetx(){returnx;}intGety(){returny;}};例如:intx=3,y=5;是错误的形式例如:Pointa;a.x=3;a.y=5;是错误的形式可以定义成员函数来实现对数据成员的赋值。在每次定义一个新对象之后调用一下该函数,就可以完成对数据成员的赋值。例如:Pointa;a.Setxy(3,5);是正确的赋值形式但是这种方法既不方便也容易忘记,如果用户不小心忘记了调用setxy来给对象赋值,那么结果有可能出错。C++提供了一个更好的方法:利用构造函数来初始化对象的数据成员。一、默认构造函数当没有为一个类定义任何构造函数的情况下,c++编译器总要自动建立一个不带参数的、函数体为空的构造函数。classPoint{intx,y;public:voidSetxy(inta,intb){x=a;y=b;}voidMove(inta,intb){x=x+a;y=y+b;}voidDisplay(){coutx,yendl;}intGetx(){returnx;}intGety(){returny;}};C++编译器为其产生给一个如下形式的默认构造函数:Point::Point(){}一旦程序定义了自己的构造函数,系统就不再提供默认构造函数。所以所有构造函数之间是关系。二、定义构造函数构造函数具有如下性质:(1)构造函数的名字与类同名。(2)构造函数尽管是一个函数,但没有任何类型,既不属于返回值函数也不属于void函数。(3)一个类可以有多个构造函数,而且,一个类的所有构造函数名字都相同,但参数各不相同。(4)当创建一个类对象时,构造函数自动执行。不能像其他函数那样进行调用。而且调用哪一个构造函数取决于传递给它的参数类型。重载classPoint{intx,y;public:Point(inta,intb){x=a;y=b;}voidSetxy(inta,intb);voidMove(inta,intb);voidDisplay();intGetx(){returnx;}intGety(){returny;}};voidPoint::Setxy(inta,intb){x=a;y=b;}voidPoint::Move(inta,intb){x=x+a;y=y+b;}voidPoint::Display(){coutx,yendl;}例2:若有Ponta;Error:noappropriatedefaultconstructoravailable.错误例1:若有Ponta(5,9);正确Point(){}正确分析错误的原因?对象a中的数据成员的值是不确定的!Point(){x=0;y=0;}对象a中的数据成员的值默认为0!用带有默认参数的构造函数来实现?classPoint{intx,y;public:Point(inta,intb){x=a;y=b;}voidSetxy(inta,intb);voidMove(inta,intb);voidDisplay();intGetx(){returnx;}intGety(){returny;}};voidPoint::Setxy(inta,intb){x=a;y=b;}voidPoint::Move(inta,intb){x=x+a;y=y+b;}voidPoint::Display(){coutx,yendl;}Point(){}Point(){x=0;y=0;}Point(inta=0,intb=0){x=a;y=b;}如果程序定义自己的有参构造函数,又想使用无参形式的构造函数,解决的方法是将相应的构造函数全部使用默认参数设计。(P794.2.4)例题:分析能否如下定义构造函数?为什么?该类中有几个构造函数?这些构造函数可否同时存在??为什么?2个不能error:'Point::Point':ambiguouscalltooverloadedfuncti