第八章面向对象程序设计8.1面向对象程序设计概述8.2类和对象8.3继承和派生8.4多态性8.5程序举例8.1面向对象程序设计(OOP)概述•基本概念ObjectOrientedProgramming对象:现实世界的实体,每个对象都有所属的类类:对一组对象共同具有的属性和行为的抽象,具有封装和隐藏性、还具有继承性。消息:向某对象请求服务的一种表达方式,是对象与外界、对象与其它对象之间联系的工具方法:对某对象接受消息后所采取的操作的描述。特点封装性继承性多态性C++中,通过类和对象实现对数据的封装,使得程序的修改维护更方便。是OOP的基础。连接类与类的层次模型,利用现有类派生出新类的过程称为类继承,支持代码重用、提供了无限重复利用程序资源的途径、节省程序开发的时间和资源,是OOP的关键。发出同样的消息被不同类型的对象接收时导致完全不同的行为,是OOP的重要补充8.2类和对象#includeiostream.hclassCircle{private:doublex,y,r;public:voidprint(){cout圆心:(x,y)endl;cout半径:rendl;}voidset(doublex1,doubley1,doubler1){x=x1;y=y1;r=r1;}};voidmain(){Circlep;p.set(0,0,2);p.print();}引例类定义数据成员成员函数定义类对象对对象调用成员函数Circle类将圆的属性(圆心坐标和半径)和操作(print、set)封装在一起上述定义的Circle类实际上也相当于一种新的数据类型,包含了数据和对数据的操作,其成员描述如下:数据成员成员函数名称含义名称功能x圆心坐标x值set设置数据成员值y圆心坐标y值print输出数据成员值r圆半径8.2.1类的定义类是一种复杂的数据类型,它是将不同类型的数据和与这些数据相关的运算封装在一起的集合体,类的结构是用来确定一类对象的行为,而这些行为是通过类的内部数据结构和相关的操作来确定的。定义格式:class类名{public:成员函数或数据成员的说明;private:成员函数或数据成员的说明;protected:成员函数或数据成员的说明;};各成员函数的实现类的说明类的说明类的说明类的说明实现部分定义类的关键字说明部分实现部分访问权限修饰符说明:定义包括说明部分和实现部分。若成员函数在说明部分已定义,则实现部分可省略。访问权限修饰符:public(公有)、private(私有)和protected(保护)缺省时为private。公有成员通常为成员函数,可在程序中引用,私有成员通常是数据成员,只有成员函数或友元函数才可引用。类体中不允许对数据成员初始化。自身类的对象不可以作为自己的成员classB{private:intyear=2002,month=10,day=12;Bb;……};错数据成员成员函数名称含义名称功能name职员姓名set设置数据成员值sex职员性别display输出数据成员值wage职员工资如,定义一个职工类,该类是对所有职工某些信息的抽象,包括如下成员:classStaff{private:charname[30];charsex;floatwage;public:voiddisplay();voidset(char*n,chars,floatw);};voidStaff::display(){coutname:sex,wageendl;}voidStaff::set(char*n,chars,floatw){strcpy(name,n);sex=s;wage=w;}说明部分实现部分作用域运算符(类体外实现时需要)8.2.2对象的定义类名仅提供一种类型定义,只有在定义属于类的变量后,系统才会为其预留空间,这种变量称为对象,它是类的实例。格式:如,假设A是一个已定义过的类,则可定义:指向A类对象的指针A类的对象对象数组类名对象名表;Aa1,*p,a[5]成员引用•一般对象成员数据成员:成员函数:对象名.成员名(参数表)•指向对象的指针的成员表示法:数据成员:成员函数:对象名.成员名对象名.成员名(参数表)对象指针名-成员名(*对象指针名).成员名或对象指针名-成员名(参数表)(*对象指针名).成员名(参数表)引用方式同结构成员#includeiostream.h#includestring.hclassStaff{private:charname[30];charsex;floatwage;public:voiddisplay(){coutname:sex,wageendl;}voidset(char*n,chars,floatw){strcpy(name,n);sex=s;wage=w;}};voidmain(){Staffs,*s1;s.set(WangQiang,'m',1526);s.display();s1=&s;s1-set(GaoLing,'f',2003);s1-display();}S1为指向s的指针可修改为如下形式吗?s.name=“WangQiang”s.sex=‘m’;s.wage=1526[例8-1]8.2.3对象的初始化1.构造函数和析构函数[例8-2]看引例的另一种实现#includeiostream.hclassCircle{private:doublex,y,r;public:voidprint(){cout圆心:(x,y)endl;cout半径:rendl;}Circle(doublex1,doubley1,doubler1){x=x1;y=y1;r=r1;}};voidmain(){Circlep(0,0,2);p.print();}构造函数、同类名1.定义的同时初始化对象2.省略对赋初值成员函数的额外调用构造函数特点析构函数特点:•若一个对象被定义在函数体内,则当该函数结束时,该对象的析构函数被自动调用。•当一个对象是使用new运算符被动态创建的,在使用delete释放时,析构函数将会被自动调用是成员函数,可写在类体内,亦可写在类体外。函数名同类名,不能指定函数类型,可以带参数。可重载,即可定义多个参数个数不同的函数。在创建对象时由系统自动调用,程序中不能直接调用。是成员函数,可写在类体内,亦可写在类体外。函数名同类名,前面多个字符“~”,不指定类型,无参。不可重载,即一个类只能定义一个析构函数。可被调用,也可由系统调用。系统自动调用情况如下:2.缺省构造函数和缺省析构函数形式:说明:若没有定义任何构造函数,系统会自动生成上述无参的缺省构造函数及析构函数若定义一个静态对象而没有指明初始化时,编译器会按缺省构造函数对对象的所有数据成员都初始化为0或空。类名::~缺省析构函数名(){}类名::缺省构造函数名(){}[例8.3]定义一个Circle1类,具有求一个圆的面积、求两个圆的面积之和,以及输出面积等功能。#includeiostream.hclassCircle1{private:doublex,y,r,s;public:voidprint(){cout圆心:(x,y)endl;cout半径:rendl;}Circle1(){}Circle1(doublex1,doubley1,doubler1){x=x1;y=y1;r=r1;}voidaddarea(Circle1p1,Circle1p2){s=3.14*(p1.r*p1.r)+3.14*(p2.r*p2.r);}voiddisp(){cout面积:sendl;}};voidmain(){Circle1p1(0,0,2),p2(1,1,4),p3;p1.print();p2.print();p3.addarea(p1,p2);p3.disp();}可缺省吗?验证一下初始化了吗#includeiostream.h#includestring.h#includestdio.hclasscount{intnum;chars[80];public:count(char*str);~count();voidprocess();};count::count(char*str){num=0;strcpy(s,str);}count::~count(){cout数字字符的个数:numendl;}voidcount::process(){inti=0;while(s[i]!='\0'){if(s[i]='0'&&s[i]='9')num++;i++;}}voidmain(){chars[80];gets(s);countc(s);c.process();}[例8.4]析构函数示例析构函数中输出处理结果(未设专门输出函数)析构函数在程序结束前由系统自动调用3.拷贝初始化构造函数[例8.5]#includeiostream.hclassCircle1{private:doublex,y,r,s;public:voidprint(){cout圆心:(x,y)endl;cout半径:rendl;}Circle1(doublex1,doubley1,doubler1){x=x1;y=y1;r=r1;}Circle1(Circle1&p){x=p.x;y=p.y,r=p.r;}};voidmain(){Circle1p1(0,0,2),p2(p1);p1.print();p2.print();}用于用已知对象初始化被创建的同类对象只有一个参数,且是对某个对象的引用常用于做函数的形参及返回值拷贝初始化构造函数(引用做参数)已知对象做初值8.2.4常对象和常成员1.常成员函数形式:类型说明符函数名(参数表)const不修改对象数据成员的成员函数才能声明为const函数构造函数和析构函数不能声明为const只有常成员函数可以操作常对象说明:[例8.6]常成员函数示例#includeiostream.hclassTime{private:inthour,minute,second;public:Time::Time(){}Time::Time(inth,intm,ints){hour=h;minute=m;second=s;}voidsettime(inth,intm,ints){hour=h;minute=m;second=s;}voidprint()const{couthour:minute:secondendl;}};voidmain(){Timet1;constTimet2(10,23,34);//定义t2为常对象t1.settime(11,15,20);t1.print();//t2.settime(4,12,15);t2.print();}前面的解释符可去掉吗不修改数据成员,定义为常函数settime函数可声明为const吗2.常数据成员对不应该被修改的数据成员声明为const,可使其受到强制保护,初始化方式与一般数据成员不同。classDecrement{private:intnum;constintdec;//将dec声明为常数据成员public:Decrement(intn,intd):dec(d){num=n;}voidfdec(){num=num-dec;}voidprint()const{coutnum=num,dec=decendl;}};初始化列表的方式初始化8.2.5静态成员静态成员的提出是为了解决数据共享的问题,它比全局变量在实现数据共享时更为安全,是实现同类多个对象数据共享的好方法。在类中,分为静态数据成员和静态函数。1。静态数据成