第8章 类与对象.docx
《第8章 类与对象.docx》由会员分享,可在线阅读,更多相关《第8章 类与对象.docx(25页珍藏版)》请在冰豆网上搜索。
第8章类与对象
主讲内容
8.1.1面向对象程序设计概述
与面向对象程序设计相对应的是面向过程程序设计,在面向过程的程序设计中,程序的核心部分是函数
把一个大的复杂的问题变成了对若干个小的简单问题的求解,这种方法我们把它称作“自顶向下,逐步求精”。
8.1.1面向对象程序设计概述
【例8.1】使用函数作为模块的程序设计方法
假设某一个企业中员工岗位分为两类,一类为技术型,一类为管理型。
现在企业需要根据员工类型和员工参加工作时间计算津贴。
假设企业员工信息存储在一个结构数组中,该结构包括了员工的编号、姓名、类型、参加工作时间等信息,要求根据输入的员工编号,查找出该员工,然后根据员工类型和参加工作时间计算津贴。
8.1.1面向对象程序设计概述
#include
#include
usingnamespacestd;
structDate{
intmonth;
intday;
intyear;};
structEmployee{
stringemployeeid;
stringname;
intkind;//员工类型标识,技术类为1,管理类为2
Dateworktime;};//查找员工
intSearchEmployee(Employee*p,intn,stringemployeeid){
8.1.1面向对象程序设计概述
inti;
for(i=0;iif((*(p+i)).employeeid==employeeid)
returni;}
return-1;}
doubleComputeAllowance(intkind,intworkyear){
if(kind==1){
if(workyear<=2000)
return10000;
else
return5000;}
else{
if(workyear<=2000)
return6000;
8.1.1面向对象程序设计概述
else
return3000;}
}
voidPrintAllowance(Employee*p,inti){
if(i==-1){
cout<<"没有与输入员工编号相匹配的员工记录"<}else
{
cout<<"员工"<<(*(p+i)).name<<"的津贴为:
"
<}
8.1.1面向对象程序设计概述
intmain(){
inti=0;
stringsearchid;
Employeeemployee[4]={
{"19900001","王军",1,3,15,1990},
{"20000001","李明",2,10,8,2000},
{"20050001","刘云",1,5,20,2005},
{"20070001","赵涛",2,8,18,2007}};
cout<<"请输入员工编号:
";
cin>>searchid;
i=SearchEmployee(employee,4,searchid);
PrintAllowance(employee,i);
return0;}
8.1.1面向对象程序设计概述
我们把整个程序过程分成三个部分:
查找员工、计算津贴和打印输出。
我们把这三个部分分别由三个函数来实现,即SearchEmployee、ComputeAllowance和PrintAllowance三个部分。
函数与数据及函数与函数的调用关系如图所示:
8.1.1面向对象程序设计概述
8.1.1面向对象程序设计概述
面向对象程序设计方法主要着眼于解决面向过程程序设计在开发大型程序时所面临的一系列缺点:
数据与操作分离、函数的串联改变、模块的可重用性差等。
面向对象程序设计的主要特点有:
抽象、封装、继承和多态
8.1.1面向对象程序设计概述
(1)抽象
抽象表示同一类事物的本质。
比如“学生”是一种抽象,它是对我们现实世界中具体学生个体的一种归纳。
(2)封装
类和对象把数据和相关的操作放在一起,作为一个整体对外界提供服务。
(3)继承
继承为代码重用提供了一种解决机制。
(4)多态
多态是面向对象程序设计的一个重要特征。
多态可以理解为:
给多个不同的对象下达同一个指令,不同的对象在接受时会产生不同的行为。
8.1.2类的声明
作为C++语言中的自定义类型,类的声明的方式为:
class类名
{
private:
私有的数据成员;
私有的成员函数;
public:
公有的数据成员;
公有的成员函数;
protected:
保护的数据成员;
保护的成员函数;
};
8.1.2类的声明
我们可以声明如下员工类:
classEmployee
{private:
stringemployeeid;
stringname;
intage;
public:
voiddisplay()
{
cout<<”编号:
”<cout<<”姓名:
”<cout<<”年龄:
”<}
};
8.1.2类的声明
private、public和protected为成员访问限定符。
用来表示类中数据成员和成员函数的访问特征。
这三种访问控制方式分别为:
(1)一个类中所有private成员(包括数据成员和成员函数)只能被本类中的成员函数访问。
友元函数和友元类例外。
(2)一个类中所有的public成员(包括数据成员和成员函数)既可以被本类中的成员函数访问,也可以被类外部的程序代码访问。
(3)protected限定符一般用于类的继承,一个类的子类被称作派生类,类的protected成员不能被类外部程序代码访问,但是可以被派生类的成员函数访问。
8.1.3类的成员函数
当一个函数属于某一个类时,我们称其为类的成员函数
我们也可以,把声明部分写在类内,把定义部分写在类的外部。
如:
classEmployee
{private:
stringemployeeid;
stringname;
intage;
public:
voiddisplay()
};
8.1.3类的成员函数
voidEmployee:
:
display()
{
cout<<”编号:
”<cout<<”姓名:
”<cout<<”年龄:
”<};
在以上类的定义中,类内只保留了成员函数display的声明,而display函数的定义写在类外。
8.1.4类与结构体
在C++中,使用struct和class都可以定义一个类。
以下代码所定义的类与之前使用class定义的类是完全相同的。
structEmployee
{private:
stringemployeeid;
stringname;
intage;
public:
voiddisplay(){
cout<<”编号:
”<cout<<”姓名:
”<cout<<”年龄:
”<};
8.1.4类与结构体
C++中使用struct和class进行类声明的主要区别为:
在struct中,不使用private、public和protected限定符定义的数据成员和成员函数被编译器默认为是public的。
而在class中没有使用限定符修饰的成员默认为private。
8.2.1对象的定义
C++中类是一种自定义数据类型,对象可以理解为使用“类”类型定义的变量
对象的定义方式也有三种:
(1)先声明类,再定义对象
如果使用8.1.3中所声明的Employee类进行对象的定义,语句为:
Employeeemployee1,employee2;
8.2.1对象的定义
(2)声明类的同时定义对象
classEmployee{private:
stringemployeeid;
stringname;
intage;
public:
voiddisplay(){
cout<<”编号:
”<cout<<”姓名:
”<cout<<”年龄:
”<}employee1,employee2;
8.2.1对象的定义
(3)直接定义对象
class
{private:
stringemployeeid;
stringname;
intage;
public:
voiddisplay()
{
cout<<”编号:
”<cout<<”姓名:
”<cout<<”年龄:
”<}employee1,employee2;
8.2.2对象成员的引用
对象成员的引用包括数据成员的引用和成员函数的引用。
需要注意的是,外部程序引用对象的成员时,只能引用对象的公有成员,而不能引用其私有和保护成员。
引用对象成员的一般形式为:
对象名.成员名
当使用对象指针时,引用指针所指向的对象成员的形式可以为以下两种:
(*指向对象的指针).成员名
指向对象的指针->成员名
8.2.2对象成员的引用
【例8.3】引用对象成员
#include
usingnamespacestd;
classDate{public:
intmonth;
intday;
intyear;
voiddisplay(){
cout<}
};
8.2.2对象成员的引用
intmain(){Datedate1,*date2;
date1.month=5;
date1.day=20;
date1.year=2010;
date1.display();
date2=&date1;
date2->month=6;
date2->day=15;
date2->year=2009;
date2->display();
return0;}
程序执行结果为:
2010-5-20
2009-6-15
8.3.1构造函数的作用
使用类定义一个对象后,对象必须经过初始化才能被使用
需要注意的是,无论是对数据成员赋值还是执行对象的初始化,都只能针对对象的公有数据成员来进行,如果对一个对象的私有数据成员赋值,会出现编译错误。
我们知道类内部的成员函数可以访问类中所有的数据成员。
所以我们可以设计一个成员函数,使用该函数进行对象的初始化操作。
8.3.1构造函数的作用
使用这类函数进行对象的初始化具有以下两个缺点:
(1)为了实现对象的初始化引入了初始化函数,增加了类的复杂性,由于该函数被声明为公有的,增加了一个由外部程序访问内部私有数据成员的接口。
(2)定义对象后如果忘记了调用初始化函数或者对一个对象进行了多次初始化函数的调用都会引起程序出错。
8.3.1构造函数的作用
为了解决对象的初始化问题,C++提供了一个特殊的成员函数来完成对象的初始化操作,即构造函数(constructor)。
构造函数具有以下几个特点:
(1)构造函数的目的就是实现对象的初始化。
(2)构造函数的名字与类名相同,不能由用户命名。
(3)构造函数没有函数返回值。
(4)构造函数不需要用户调用,对象建立时构造函数会自动执行。
8.3.1构造函数的作用
【例8.5】使用类的构造函数实现对象的初始化
#include
usingnamespacestd;
classDate
{private:
intmonth;
intday;
intyear;
public:
Date()//缺省构造函数
{
8.3.1构造函数的作用
month=0;
day=0;
year=0;
}
voiddisplay(){
cout<}
voidsetDate(intm,intd,inty){
month=m;
day=d;
year=y;
}
};
8.3.1构造函数的作用
intmain(){
Datedate1,date2;
date1.display();
date1.setDate(5,20,2010);
date1.display();
date2.display();
return0;}
程序运行结果为:
0-0-0
2010-5-20
0-0-0
8.3.2带参数的构造函数
C++中把一个类的无参构造函数称作缺省构造函数。
构造函数不能像其他成员函数一样被显式调用。
除了缺省构造函数,C++的类还允许使用带有参数的构造函数
8.3.2带参数的构造函数
【例8.6】使用类的带参数的构造函数实现对象的初始化
#include
usingnamespacestd;
classDate
{private:
intmonth;
intday;
intyear;
public:
8.3.2带参数的构造函数
Date(intm,intd,inty)//带参数的构造函数
{
month=m;
day=d;
year=y;
}
voiddisplay(){
cout<}
};
8.3.2带参数的构造函数
intmain()
{
Datedate1(5,20,2010),date2(6,15,2009);
date1.display();
date2.display();
return0;
}
程序运行结果为:
2010-5-20
2009-6-15
8.3.3构造函数重载
【例8.7】构造函数的重载
#include
usingnamespacestd;
classDate
{private:
intmonth;
intday;
intyear;
public:
Date(){//缺省构造函数
8.3.3构造函数重载
month=0;
day=0;
year=0;
}
Date(intm,intd,inty){//带参数的构造函数
month=m;
day=d;
year=y;
}
voiddisplay(){
cout<}
};
8.3.3构造函数重载
intmain()
{
Datedate1(5,20,2010);//调用构造函数Date(intm,intd,inty)
Datedate2;//调用构造函数Date()
date1.display();
date2.display();
return0;
}
程序运行结果为:
2010-5-20
0-0-0
8.3.3构造函数重载
使用构造函数需要注意以下两点:
(1)C++的每一次对象创建都会伴随着构造函数的调用,即使用户没有给类定义构造函数。
(2)只要用户在类中定义了构造函数,C++编译系统将不会再提供默认的缺省构造函数。
8.3.4拷贝构造函数
拷贝构造函数用来创建一个新的对象,该对象是另外一个对象的复制品
如果一个类没有定义拷贝构造函数,C++会提供一个默认的拷贝构造函数,该拷贝构造函数的功能把被复制对象的数据成员一一对应地复制到新对象中。
8.3.4拷贝构造函数
【例8.8】使用拷贝构造函数
#include
usingnamespacestd;
classDate{private:
intmonth;
intday;
intyear;
public:
Date(intm,intd,inty){//带参数的构造函数
month=m;
day=d;
year=y;
}
8.3.4拷贝构造函数
Date(constDate&d)//拷贝构造函数
{
month=d.month;
day=d.day;
year=d.year;
cout<<”拷贝构造函数被调用!
”<}
voiddisplay(){
cout<}
};
8.3.4拷贝构造函数
intmain(){
Datedate1(5,20,2010);//调用构造函数Date(intm,intd,inty)
Datedate2=date1;//调用拷贝构造函数Date(constDate&d)
date1.display();
date2.display();
return0;
}
程序运行结果为:
拷贝构造函数被调用!
2010-5-20
2010-5-20
8.4析构函数
当一个对象被撤销时,撤销前会调用类的析构函数。
析构函数(destructor)是类的一个特殊成员函数,析构函数的函数名与是在类名的前边加上一个”~”符号。
与构造函数一样析构函数没有函数返回值,但是与构造函数不同,析构函数没有函数参数,所以析构函数不能被重载。
一个类只能拥有一个析构函数。
在析构函数中完成内存或其他资源的回收工作以防止资源泄漏。
构造的顺序与析构的顺序相反。
8.5类的静态成员
C++提供了另外一种成员,这种成员只属于类本身,不属于类的对象,这种成员我们称作类的静态成员。
类的静态成员包括静态数据成员和静态成员函数。
8.5.1静态数据成员
如果我们给类的某一个数据成员的声明语句前边添加一个static关键字,则该成员就成为了类的静态数据成员。
如:
classDate
{
private:
intmonth;
intday;
intyear;
public:
staticintn;//类的静态数据成员
};
8.5.1静态数据成员
静态数据成员可以被初始化,不过初始化语句只能放在类外。
静态数据成员的初始化形式为:
数据类型类名:
:
静态数据成员名=初值;
如:
intDate:
:
n=0;
8.5.2静态成员函数
在一个类中成员函数的声明前边加上static,该成员函数就成为了类的静态成员函数。
classDate{
private:
intmonth;
intday;
intyear;
public:
staticintn;//类的静态数据成员
staticvoiddisplayObjectNum(){
cout<<”Date对象的个数为:
”<};
8.5.2静态成员函数
类的静态成员函数只能访问类的静态成员(包括静态数据成员和静态成员函数),不能访问类内的其他数据成员和成员函数
【例8.11】使用类的静态数据成员和静态成员函数
#include
#include
usingnamespacestd;
classDate
8.5.2静态成员函数
{private:
intmonth;
intday;
intyear;
staticintn;
public:
Date(intm,intd,inty){//带参数的构造函数
month=m;
day=d;
year=y;
n++;
}
8.5.2静态成员函数
Date(constDate&d){//拷贝构造函数
month=d.month;
day=d.day;
year=d.year;
n++;}
~Date(){//析构函数
n--;}
voiddisplay(){
cout<8.5.2静态成员函数
staticvoiddisplayObjectNum(){
cout<<"Date对象的个数为:
"<};
intDate:
:
n=0;
intmain(){
Datedate1(5,20,2010);
Date:
:
displayObjectNum();
Datedate2=date1;
Date:
:
displayObjectNum();
8.5.2静态成员函数
date1.display();
date2.display();
return0;
}
程序运行结果为:
Date对象的个数为:
1
Date对象的个数为:
2
2010-5-20
2010-5-20
8.6友元
有些情况下需要开放类的私有成员给特定的函数或类来访问,这时可以把该特定函数或类声明为一个类的友元(friend).
友元可以访问具有友好关系的类的私有成员。
友元包括友元函数和友元类。
8.6.1友元函数
在类中声明该函数为友元函数的方法:
在类中写上函数的声明,并在前边加上friend关键字。
8.6.1友元函数
【例8.12】使用友元函数访问类的私有成员。
#include
#include
usingnamespacestd;
classDate
{private:
intmonth;
intday;
intyear;
public:
friendvoidmodifyDate(Date&date,intmonth,intday,intyear);//声明类Date的友元函数
8.6.1友元函数
modifyDate(date1,6,15,2009);
Date(intm,intd,inty){//带参数的构造函数
month=m;
day=d;
year=y;}
Date(constDate&d){/