复习-第八章面向对象程序设计_第1页
复习-第八章面向对象程序设计_第2页
复习-第八章面向对象程序设计_第3页
复习-第八章面向对象程序设计_第4页
复习-第八章面向对象程序设计_第5页
已阅读5页,还剩50页未读 继续免费阅读

下载本文档

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

文档简介

第八章面象程序设计象程序设计概述面结构类和对象继承和派生多态性程序举例8.1面象程序设计(OOP)概述Object

Oriented

Programming基本概念对象:现实世界的实体,每个对象都有所属的类类:

对一组对象共同具有的属性和行为的抽象,具有封装和隐藏性、还具有继承性。消息:向某对象请求服务的一种表达方式,是对象与外界、对象与其它对象之间联系的工具方法:对某对象接受消息后所采取的操作的描述。特点封装性C++中,通过类和对象实现对数据的封装,使得程序的修改维护更方便。是OOP的基础。继承性连接类与类的层次模型,利用现有类派生出新类的过程称为类继承,支持代码重用、提供了无限重复利用程序资源的途径、节省程序开发的时间和资源,是OOP的关键。多态性发出同样的消息被不同类型的对象接收时导致完全不同的行为,是OOP的重要补充说明结构类型的关键字8.2结构C++中的类从C语言中的结构概念演变而来结构类型说明形式struct

结构类型标识符{结构成员1;结构成员2;┆结构成员n;};类型可任意(不能为该结构自身)struct

date{int

month;int

day;int

year;};struct

man{char

name[15];char

sex;int

age;date

birthday;};如,说明一个结构类型date,含三个整型数据成员在此基础上,又可说明另一个结构类型manNamesexagebirthdaymonthdayyearstruct

man结构类型结构变量定义struct

man man1,

man2;先说明结构类型再定义结构变量在说明结构数据类型的同时定义结构变量省略结构标识符直接定义结构类型变量struct

man{

char

name[15];char

sex;int

age;struct

date

birthday;}

man1,

man2;struct{

char

name[15];char

sex;int

age;struct

date

birthday;}

man1,

man2;无类型名变量结构变量的形式:结构变量名.成员名或

(*指向结构的指针).成员名指向结构的指针->成员名或通过指向结构的指针结构变量成员成员

运算符优先级最高的四个运算符之一括号不能少strcpy

(,

"Fang

Min");p->birthday.month

=

8;如,假设有定义manm,*p=&m;则可如下

结构成员8.3类和对象#include"iostream.h"classCircle{private:double

x,y,r;public:voidprint(){cout<<"圆心:("<<x<<","<<y<<")"<<endl;cout<<"半径:"<<r<<endl;}void

set(double

x1,double

y1,double

r1){

x=x1;

y=y1;

r=r1;}};void

main(){Circle

p;}引例类定义数据成员成员函数定义类对象p.set(0,0,2);p.print();对对象调用成员函数Circle类将圆的属性(圆心坐标和半径)和操作(print、set)封装在一起上述定义的Circle类实际上也相当于一种新的数据类型,包含了数据和对数据的操作,其成员描述如下:数据成员成员函数名称含义名称功能x圆心坐标x值set设置数据成员值y圆心坐标y值print输出数据成员值r圆半径8.3.1类的定义class

类名{public:<成员函数或数据成员的说明>;private:<成员函数或数据成员的说明>;protected:<成员函数或数据成员的说明>;};<各成员函数的实现>类是一种复杂的数据类型,它是将不同类型的数据和与这些数据相关的运算封装在一起的集合体,类的结构是用来确定一类对象的行为,而这些行为是通过类的数据结构和相关的操作来确定的。定义格式:

定义类的关键字说明部分实现部分访问权限修饰符说明:定义包括说明部分

部分。若成员函数在说明部分已定义,则实现部分可省略。权限修饰符:public(公有)、private(私有

)和protected(保护)缺省时为private。公有成员通常为成员函数,可在程序中

,私有成员函数才可

。通常是数据成员,只有成员函数或类体中不允许对数据成员初始化。自身类的对象不可以作为自己的成员classB{private:int

year=2002,

month=10,

day=12;Bb;……};错数据成员 成员函数名称 含义 名称 功能name

职员

set

设置数据成员值sex

职员

display

输出数据成员值wage

职员工资如,定义一个职工类,该类是对所有职工某些信息的抽象,包括如下成员:classStaff{private:char

name[30];char

sex;float

wage;public:voiddisplay();};void

Staff::display(){cout<<name<<":"<<sex<<","<<wage<<endl;}void

Staff::set(char

*n,char

s,float

w){strcpy(name,n);sex=s;void

set(char

*n,char

s,float

w);

wage=w;}说明部分实现部分作用域运算符(类体外实现时需要)8.3.2对象的定义类名仅提供一种类型定义,只有在定义属于类的变量后,系统才会为其预留空间,这种变量称为对象,它是类的实例。格式:指向A类对象的指针A类的对象对象数组类名

对象名表;如,假设A是一个已定义过的类,则可定义:A

a1,*p,a[5]成员一般对象成员数据成员:成员函数:<对象名>.<成员名>(<参数表>)指

象的指针的成员表示法:对象名.成员名对象名.成员名(参数表)对象指针名->成员名(*对象指针名).成员名数据成员:或成员函数:对象指针名->成员名(参数表)(*对象指针名.成员名(参数表)#include

"iostream.h"#include

"string.h"class

Staff{private:char

name[30];char

sex;float

wage;public:void

display(){cout<<name<<":"<<sex<<",

"<<wage<<endl;}void

set(char

*n,char

s,float

w){strcpy(name,n);sex=s;

wage=w;}};void

main(){Staff

s,*s1;s.set(“WangQiang”,‘m’,1526);s.display();s1=&s;s1->set("GaoLing",'f',2003);s1->display();}S1为指向s的指针可修改为如下形式吗=

“WangQiangs.sex=‘m’;s.wage=1526[例8-1]8.3.3对象的初始化1.构造函数和析构函数[例8-2]看引例的另一种实现#include"iostream.h"classCircle{private:double

x,y,r;public:voidprint(){cout<<"圆心:("<<x<<","<<y<<")"<<endl;cout<<"半径:"<<r<<endl;}Circle(double

x1,double

y1,double

r1){x=x1;

y=y1;

r=r1;}};void

main(){Circle

p

(0,0,2);p.print();}构造函数、同类名定义的同时初始化对象省略对赋初值成员函数的额外调用构造函数特点是成员函数,可写在类体内,亦可写在类体外。函数名同类名,不能指定函数类型,可以带参数。可重载,即可定义多个参数个数不同的函数。在创建对象时由系统自动调用,程序中不能直接调用。析构函数特点:是成员函数,可写在类体内,亦可写在类体外。函数名同类名,前面多个字符“~”

,不指定类型,无参。不可重载,即一个类只能定义一个析构函数。可被调用,也可由系统调用。系统自动调用情况如下:若一个对象被定义在函数体内,则当该函数结束时,该对象的析构函数被自动调用。当一个对象是使用new运算符 态创建的,在使用delete

时,析构函数将会被自动调用2.缺省构造函数和缺省析构函数形式:说明:若没有定义任何构造函数,系统会自动生成上述无参的缺省构造函数及析构函数若定义一个静态对象而没有指明初始化时,编译器会按缺省构造函数对对象的所有数据成员都初始化为0或空。<类名>::~<缺省析构函数名>(){

}<类名>::<缺省构造函数名>(){

}[例8.3]

定义一个Circle1类,具有求一个圆的面积、求两个圆的面积之和,以及输出面积等功能

。#include"iostream.h"classCircle1{private:double

x,y,r,s;public:voidprint(){cout<<"圆心:("<<x<<","<<y<<")"<<endl;cout<<"半径:"<<r<<endl;}Circle1(){

}Circle1(double

x1,double

y1,double

r1){

x=x1;

y=y1;

r=r1;}void

addarea(Circle1

p1,Circle1

p2){s=3.14*(p1.r*p1.r)+3.14*(p2.r*p2.r);}voiddisp(){ cout<<"面积:"<<s<<endl;}};voidmain(){Circle1

p1(0,0,2),p2(1,1,4),p3;p1.print();p2.print();p3.addarea(p1,p2);p3.disp();}可缺省吗?验证一下初始化了吗#include<iostream.h>#include<conio.h>classcount{intnum;public:count();~count();voidprocess();};count::count(){num=0;}count::~count(){cout<<"字符个数:"<<num<<endl;}voidcount::process(){while(cin.get()!='\n')num++;cout<<endl;

}voidmain(){count

c;cout<<"输入一个句子:"

;cess();}[例8.4]

析构函数示例析构函数中输出处理结果(未设专门输出函数)析构函数在程序结束前由系统自动调用3.拷贝初始化构造函数[例8.5]#include

"iostream.h"class

Circle1{private:double

x,y,r,s;public:void

print(){cout<<"圆心:("<<x<<","<<y<<")"<<endl;cout<<"半径:"<<r<<endl;}Circle1(double

x1,double

y1,double

r1){ x=x1;

y=y1;

r=r1;}Circle1(

Circle1

&p){x=p.x;

y=p.y,

r=p.r;}};void

main(){Circle1

p1(0,0,2),p2(p1);p1.print();p2.print();}用于用已知对象初始化被创建的同类对象只有一个参数,且是对某个对象的常用于做函数的形参及返回值拷贝初始化构造函数(做参数)已知对象做初值8.3.4常对象和常成员1.常成员函数形式:类型说明符 函数名(参数表)

const为const函数不修改对象数据成员的成员函数才能构造函数和析构函数不能 为const只有常成员函数可以操作常对象说明:[例8.6]常成员函数示例#include"iostream.h"class

Time{private:inthour,minute,second;public:Time::Time(){

}Time::Time(int

h,int

m,int

s){hour=h;

minute=m;

second=s;}void

settime(int

h,int

m,int

s){hour=h;

minute=m;

second=s;}voidprint()const{cout<<hour<<":"<<minute<<":"<<second<<endl;}};voidmain(){Time

t1;const

Time

t2(10,23,34);//定义t2为常对象t1.settime(11,15,20);t1.print();//t2.settime(4,12,15);t2.print();}前面的解释符可去掉吗不修改数据成员,定义为常函数settime函数可为const吗2.常数据成员对不应该被修改的数据成员

为const,可使其受到强制保护,初始化方式与一般数据成员不同。为常数据成员class

Decrement{private:int

num;const

int

dec;//将decpublic:Decrement(int

n,int

d):dec(d){num=n;}void

fdec(){num=num-dec;

}void

print()const{cout<<"num="<<num<<",dec="<<dec<<endl;

}};初始化列表的方式初始化6.3.5静态成员静态成员的提出是为了解决数据共享的问题,它比全局变量在实现数据共享时更为安全,是实现同类多个对象数据共享的好方法。在类中,分为静态数据成员和静态函数。1。静态数据成员初始化格式:数据类型 类名::静态数据成员=值是类的成员,被所有对象所共享,在内存中只存贮一次定义或说明时前面加关键字static初始化在类行,不加static和权限修饰符[例8.7] 静态数据成员示例程序、初始化的位置和限通过以下程序了解静态数据成员的定及具有类对象共享的属性。#include

<iostream.h>class

Tc{private:int

i;static

int

k;public:Tc(

){i=0;

i++;

k++;}void

display(){cout<<i<<","<<k;}};int

Tc::k=0;void

main(){Tc

A,B;display();display();}运行结果:静态变量静态变量初始化创建A时k值0->1创建B时k值1->2。1,21,22.静态成员函数静态成员函数中数据成员的 也有区别:[例8.8]静态成员函数应用程序示例静态成员函数是类的成员函数,而非对象的成员。调用形式:类名::静态成员函数名(参数表)对静态数据成员,直接对非静态数据成员,通过对象#include

<iostream.h>class

Tc{private:int

A;

static

int

B;public:Tc(int

a){A=a;

B+=a;}static

void

display(Tc

C){cout<<C.A<<B;}};int

Tc::B=2;void

main(){Tc

A(2),B(4);Tc::display(A);Tc::display(B);}静态成员函数的调用非静态数据成员的静态数据成员的引用通过该程序了解程序中静态成员函数的调用方式以及静态成员函数中静态数据成员和非静态数据成员的 方式8.3.6

函数void

Cpoint::print(){cout<<X<<Y

;}double

dist(Cpoint

&a,Cpoint

&b){int

dx=a.X-b.X;intdy=a.Y-b.Y;return

sqrt(dx*dx+dy*dy);}void

main(){Cpoint

p1(3,4),p2(6,8);p1.print();p2.print();double

d=dist(p1,p2);

/*不是成员函数不需对象表示,直接调用*/cout<<"Distance

is

"<<d<<endl;}函数说明前不能加friend为非成员函数可 类中私有成员说明时前面加关键字friend标识[例8.9] 函数示例程序#include

<iostream.h>#include

<math.h>class

Cpoint{private:int

X,Y;public:Cpoint(int

x,

int

y){X=x;

Y=y;}void

print();friend

double

dist(Cpoint

&a,Cpoint

&b);};计算机系学生本科生系行政管理教务教师教职工8.4

继承和派生基类(父类)派生类(子类)多继承单继承class

Cylinder1:public

Circle{private:double

h;public:void

print(){Circle::print();cout<<"圆柱高:"<<h<<endl;}void

set(double

x1,double

y1,double

r1,double

h1){

Circle::set(x1,y1,r1);h=h1;}};class

Cylinder{private:double

x,y,r,h;public:void

print(){cout<<"圆心:("<<x<<","<<y<<")"<<endl;cout<<"半径:"<<r<<",圆柱高:"<<h<<endl;}void

set(double

x1,double

y1,double

r1,double

h1){

x=x1;

y=y1;

r=r1;

h=h1;}};对比如下两个圆柱体类的定义全部数据成员重新定义只定义一个新成员(Circle中没有)通过调用Circle类成员函数输出Circle类成员从Circle类中派生而来8.4.2单继承1.派生类的定义格式public(公有基类)private(私有基类)protected(保护基类)class

派生类名:

继承方式

基类名{派生类新定义成员};若要在派生类Cylinder1中再增加一个成员函数

volume,用以求圆柱体的体积,则该成员函数能否如下实现:double

Cylinder1::volume(){return(3.14*r*r*h);}错!r是Circle类的私有成员,不能被派生类2.继承方式public,private和

protected是三种常用的继承方式,继承方式的不同决定了派生类对基类成员的

权限不同。基类私有成员(private)公有成员(public)保护成员(protected)私有派生类(private)不可

的成员私有成员私有成员公有派生类(public)不可

的成员公有成员保护成员保护派生类(protected)不可

的成员保护成员保护成员派生类的继承关系[例8.10]分析下列程序中的权限,并回答所提的问题。#include

<iostream.h>class

A{public:voidf1();A(

){i1=10;j1=11;}protected:intj1;private:inti1;};class

B:public

A{public:voidf2(

);B(){i2=20;j2=21;}protected:intj2;private:inti2;};class

C:public

B{public:voidf3();C(

){i3=30;j3=31;}protected:intj3;private:inti3;};voidmain(){A

a;B

b;C

c;}f2()能否

f1(),i1,j1?能

f1()、j1,不能

i1b能否

f1(),i1,j1?能

f1(),不能

i1和j1(3)

f3()能否

f2()、i2和j2以及f1(),j1和i1?f3能

f2()和j2,以及f1()和j1,但不能

i1和i2(4)c能否

f2(),i2和j2以及f1(),j1和i1?能

f2()和f1(),其它的都不能#include

"iostream.h"class

Circle{private:double

x,y,r;public:void

print(){cout<<"圆心:("<<x<<","<<y<<")";cout<<endl<<"半径:"<<r<<endl;}void

set(double

x1,double

y1,double

r1)r=r1;

}{

x=x1;

y=y1;double

getr(){return

r;}}};void

main(){Cylinder1

p;p.set(0,0,2,3);};该函数返回值为圆半径,为派生类能使用半径提供一个接口class

Cylinder1:public

Circle{private:double

h;public:void

print(){Circle::print();cout<<"圆柱高:"<<h<<endl;}void

set(double

x1,double

y1,double

r1,double

h1){

Circle::set(x1,y1,r1);h=h1;}double

volume(){double

R=getr();return(3.14*R*R*h);派生类可基类公有成员p.print();cout<<"volume="<<p.volume();}[例8.11]派生类示例程序3.构造函数和析构函数派生类的构造函数除了对自己的数据成员初始化外,还负责调用基类构造函数使基类的数据成员得以初始化,当对象被删除时,派生类的析构函数被执行,同时基类的析构函数也将被调用。格式:派生类名(派生类构造函数 数表):基类构造函数(参数表1){<派生类中数据成员初始化>};说明:基类中有缺省的构造函数或没定义构造函数,则派生类构造函数的定义中可省略对基类构造函数的调用,而隐式调用缺省构造函数。基类构造函数中,只有有参的构造函数,则派生类构造函数中必须调用基类构造函数,提供将参数传递给基类构造函数的途径派生类构造函数的调用顺序为先基类,后派生类。派生类析构函数的执行顺序为先派生类,后基类。#include"iostream.h"#include

"string.h"class

Staff{private:char

name[30];char

sex;floatwage;public:voiddisplay(){cout<<name<<":"<<sex<<",

"

<<age<<endl;}Staff(char

*n,char

s,float

w){

strcpy(name,n);sex=s;

wage=w;}};class

Staff1:public

Staff{private:intwt;public:}{wt=t;}double

addwage(){return(wt/10*80);}voiddisplay(){

Staff::display();cout<<wt<<",

"

<<addwage()<<end};void

main(){Staff1s("WangQiang",'m',1526,21);s.display();}[例8.12]派生类构造函数示例程序派生类构造函数中调用基类构造函数Staff1(char

*n,char

s,float

w,int

t):Staff(n,s,w8.5多态性发出同样的消息被不同类型的对象接收时导致完全不同的行为。函数重载(已介绍过)运算符重载基于虚函数的多态性8.5.1运算符重载赋予已有的运算符多重含义,通过重新定义运算符使它能够用于特定类的对象以完成特定的功能。[例8.13]重载“+”运算,用以实现两个字符串的连接#include

"iostream.h"#include

"string.h"#include

"stdio.h"class

Str{private:char

*s;int

len;public:Str(){

}Str(char*s1){

len=strlen(s1);s=new

char[len];strcpy(s,s1);}void

print(){cout<<s<<endl;

}Str

operator+(Str

s1){

return(strcat(s,s1.s));

}};void

main(){char

str1[100],str2[100];gets(str1);

gets(str2);Strs1(str1),s2(str2),s3;s3=s1+s2;s3.print();}对加法运算符进行重载s3=s1.operator+(s2)重载形式:重载为类的成员函数:类名operator运算符(参数表)程序中表达形式:c1运算符

c2重载为类的 函数:friend类名operator运算符(参数表程序中表达形式:c1运算符

c2编译程序解释形式:operator 运算符(c1,c2)将例8.13中的加法运算符重载为 函数的形式如下:friend

Str

operator+(Str

s1,Str

s2){return(strcat(s1.s,s2.s));}编译程序解释形式:隐含了指向c1的this指针c1

operator 运算符(c2)this

指针无需定义而隐含于每个类的成员函数中指向正在被某个成员函数操作的对象可以用*this来标识调用该成员函数的对象通常情况下,程序中并不显式地使用this指针[例8.14]自增运算符重载(this

指针使用示例)#include"iostream.h"class

A{private:intx;public:A(int

x1){x=x1;

}voidprint(){cout<<x<<endl;}A

operator++(){x++;return(*this);}};voidmain(){A

a(5);(++a).print();}返回调用成员函数的对象自身自增重载运算作用于A类对象a等价于如下两条语句:++a;a.print();8.5.3虚函数虚函数说明方式virtual

类型说明符 函数名 (参数表)虚函数是动态联编的基础,它是一种非static的成员函数实现动态联编的条件基类中有说明的虚函数调用虚函数操作的只能是对象指针或对象

,否则仍为静态联编[例8.15]虚函数示例程序#include"iostream.h"class

Animal{public:voidcharacter(){cout<<"动物特征:不同.\n";}virtualfood(){cout<<"动物食物:不同.\n";}};class

Giraffe:public

Animal{public:voidcharacter(){cout<<"长颈鹿特征:长颈.\n";}virtualfood(){cout<<"长颈鹿食物:树叶.\n";}};class

Elephant:public

Animal{public:voidcharacter(){cout<<"大象特征:长鼻子.\n";}virtualfood(){cout<<"大象食物:草.\n";}};void

f(Animal

*p)//形参数基类指针{p->character();p->food();}void

main(){Giraffe

g;f(&g);

//实参为派生类对象的地址Elephante;f(&e);

//实参为派生类对象的地址}观察运行结果voidf(Animal

&p)//形参为基类对象的{p.character();p.food();}voidmain(){Giraffe

g;f(g);//实参为派生类对象

Elephant

e;f(e); //实参为派生类对象}void

f(Animal

p)//形参为基类对象{p.character();p.food();}void

main(){Giraffeg;f(g);//实参为派生类对象

Elephant

e;f(e); //实参为派生类对象}若将程序的相应部分修改为如下两种形式,再观察运行结果从上述程序中可见:只有当虚函数操作的是指 象的指针或是对象的

时,对该虚函数调用采取的才是动态联编。虚函数使用说明:派生类中的虚函数应与基类中的虚函数具有相同的名称、参数个数及参数类型。可以只将基类中的成员函数显式地说明为虚函数,而派生类中的同名函数也隐含为虚函数。1.纯虚函数是一种没有函数体特殊的虚函数,当在基类中不能对虚函数给出有意义的实现,而将其说明为纯虚函数,它的实现留给派生类去做。格式:8.5.4抽象类virtual

类型

函数名

(参数表)=0;2.抽象类是带有纯虚函数的特殊类,主要作用是将有关的子类组织在一个继承层次结构中,由它来为它们提供一个公共的根。只能用作其它类的基类,不能建立抽象类对象可说明抽象类指针和

,指向其派生类,进而实现多态性。不能用作参数类型、函数返回类型或强制转换的类型。[例8.16]抽象类示例程序#include

<iostream.h>#include

<math.h>class

base{protected:int

x,y;public:virtual

void

setx(int

i,int

j=0){x=i;

y=j;}virtual

void

disp()=0;};class

square:

public

base{public:void

disp(){cout<<x*x<<endl;}};class

cube:

public

base{public:void

disp(){cout<<x*x*x<<endl;}};class

chpow:

public

base{public:void

disp(){cout<<pow(x,y);}};void

main(){base

*ptr;square

B;cube

C;chpowD;ptr=&B;ptr->setx(5);ptr->disp();ptr=&C;ptr->setx(6);ptr->disp();ptr=&D;ptr->setx(3,4);ptr->disp();}抽象类指针派生类抽象类指针指向不同的派生类对象B、C、D,实现多态性8.6程序举例类名数据成员成员函数vehicle名称含义名称功能wheels车轮个数vehicle初始化数据成员weight车重getwheels、getweight分别获得各数据成员值print输出各数据成员值truckwheelsweight基类vehicle类成员truck初始化数据成员的值(通过调用基类的构造函数初始化基类成员)payload载重量efficiency求卡车的载重效率print输出数据成员的值(通过调用基类的print函数输出基类成员的值)[例8.17]定义一

温馨提示

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

评论

0/150

提交评论