第 8 章:类和数据抽象 (i)

34
8 8 第第第第第第 第第第第第第 (I) (I) 第第第第1. 第第第第第第第第第第第第第第 2. 第第第第 C++ 第第第 ( 第第第第第第 ) 3. 第第第第第第第第第第第第第第第第 4. 第第第第第第第第第第第第第第第第

Upload: zelda-rutledge

Post on 31-Dec-2015

134 views

Category:

Documents


0 download

DESCRIPTION

第 8 章:类和数据抽象 (I). 本章目标:. 1. 理解数据封装和数据隐藏的概念. 2. 学会建立 C++ 中的类(抽象数据类型). 3. 了解类的数据成员和成员函数的属性. 4. 掌握类的数据成员和成员函数的使用. §8.1 引言. 一、面向对象的概念. 面向对象的技术有三个方面:.  面向对象分析 (OOA) [Object_Oriented Analysis].  面向对象设计 (OOD) [Object_Oriented Design].  面向对象程序设计 (OOP) [Object_Oriented Programming]. - PowerPoint PPT Presentation

TRANSCRIPT

第第 88 章:类和数据抽象章:类和数据抽象 (I)(I)

本章目标:

1. 理解数据封装和数据隐藏的概念

2. 学会建立 C++ 中的类 ( 抽象数据类型 )

3. 了解类的数据成员和成员函数的属性

4. 掌握类的数据成员和成员函数的使用

§8.1 引言

一、面向对象的概念

面向对象的技术有三个方面: 面向对象分析 (OOA) [Object_Oriented Analysis]

面向对象程序设计 (OOP) [Object_Oriented Programming]

面向对象设计 (OOD) [Object_Oriented Design]

二、 对象的定义

1. 广义定义:一切事物都是对象

如:树、猫、飞机

问题:这些对象是否具有一种类在的相似?

树:有树枝,树干,树叶,…;可以净化空气,美化环境、…

猫:有毛,四只脚,… ; 可以捉老鼠 , …

飞机:有机翼,机身,… ; 可以飞 , …

2. 对象的定义:

对象是这样一种实体:它具有名字,自身状态,自身功能。

可表示成:

OBJ=< ID . MS . DS . MI> 对象可受理的消息的集合

对象的数据结构对象可受理的操作的集合

对象的标识

三、面向对象程序设计 (OOP)

关键思想:模拟人类认识问题的过程 分类。

具体做法:把系统中的所有资源都看成对象,每个对象把一组数据和一组过程或函数封装在一起。

特点:具有信息隐藏 ( 封装 ) 的功能。

四、 C/C++程序设计的风格差异

• C 程序设计:以建立函数模块为主

• C++ 程序设计:

以建立类为主。 ( 类中既有数据部分,也有函数部分 )

类的设计是对象为核心。( 从对象的角度来建立类 )

§8.2 回顾 C 语言中的结构数据类型1. C 语言中定义的结构类型,其成员不允许有函数,例如:

struct Temp{ int num; float vol; char vh;};

结构型变量的定义: 在 C 中: strut Temp exp, *expt;

在 C++ 中: 1. struct Temp exp, *expt;

2. Temp exp, expt;

结构成员的访问:exp.num;

expt>num;

(*expt).num;等价的

2. C++ 中的结构类型,其成员允许有函数,例如:struct Date{ unsigned int day; unsigned int month; unsigned int year; void plan(int d, int m, int y );};

若有:  Date myholiday; 则: myholiday.plan(d, m, y);

例 1 :

给定三角形的三条边,计算三角形的面积和周长。

分析:假定三角形的边长分别为: a 、 b 、 c 。取s=(a+b+c)/2 ,则三角形面积为:

用两种不同的实现方法来实现: (1) 结构化方法( C/C++ 均适用) example8_1a.cpp(p.227)

(2) 在结构类型中添加成员函数的方法 (C++ 适用 )

example8_1b.cpp(p.228)

area _ triangle s(s a)(s b)(s c)

讨论1. 三角形面积的计算形式不同; area=area(a,b,c); area=TriAng.area(TriAng.a,TriAng.b,TriAng.c);2.成员函数的定义形式:double Shape::area(double a,double b,double c){ ……}3. 成员函数 area() 不允许单独调用。

讨论 程序存在的问题:1. 对不合法的数据没有检验,有可能导致错误的结果;

例如:如果输入了不合法的值:负数、字符(如: 5 , t )等,程序仍然会使用不正确的值进行计算。

2. 程序可直接修改成员的值;

改进方案:1. 增加一个函数,用来检验输入数据的合法性。

2. 采用“类”数据类型,加强数据的封装性。

§8.3 C++中的数据类型——类 在 C++ 中,类是一种自定义的数据类型。一、类型定义 一般形式:

class < 类名 > {public: // 数据成员声明; // 成员函数声明;protected: // 数据成员声明; // 成员函数声明;private: // 数据成员声明; // 成员函数声明;};

例如 : 定义一个三角形类class Triangle{public: Triangle (); void setSide(float x,float y,float z); float area(); int isTriangle();private: float a,b,c;};

几点说明1. 类定义中的两个关键字 :public 、 private

实现了数据封装;2. public: 提供给用户的接口。可以通过该类的

对象直接引用。(其下的成员函数可以被本类中的数据成员和成员函数使用)

3. private: 用来描述该类对象的属性,不允许直接访问,只有成员函数或经特殊说明的函数才可以引用它们,(其下的成员函数或数据成员只能被本类中所提供的成员函数使用)

几点说明4. protected :主要是用于继承关系(略)。

5. public 、 private 和 protected 代表访问权限。

与先后顺序无关,允许多次出现。

二、实现部分

对类中各成员函数进行定义。 一般形式: 函数返回值类型 类名 :: 函数名 ( 参数列表 ){ 函数语句体}

例如, Triangle 类中成员函数:Triangle:: Triangle (){ a=b=c=0;}

二、实现部分void Triangle::setSide(float x,float y,float z){ a=x;b=y;c=z;}float Triangle::area(){ float s; s=(a+b+c)/2; // 三角形周长的一半 return sqrt(s*(s-a)*(s-b)*(s-c)); // 计算三角形面积}int Triangle:: isTriangle(){ if((a+b)>c && (b+c)>a && (a+c)>b)) // 满足构成三角形的条件 return 1; else return 0;}

说明:1.与类同名的成员函数称为“构造函数”。 如: Triangle()

2. 构造函数的一个重要作用:初始化类对象的数据成员。3.构造函数的调用时机:对象生命开始的时候,由系统自动调用。注:关于构造函数的性质将在后续章节 ( 第 9 章 ) 叙述。注意: 1. 成员函数也可以在类声明中直接定义( p.231 )。 2. 不建议这么做。

一、类对象的定义

< 类名 > < 对象名 >< 类名 > < 对象名 >

例如: Triangle triangle ; //Shape 类的对象 Triangle ArrTriangle[5] ; //Shape 类的对象数组 Triangle *PointTriangle ; //Shape 类的指针对象 Triangle &RefTriangle= triangle ; //Shape 类对象的别名

注意:对象不能直接使用 private 中的成员: triangle.a 是错误的。

§8.4 类成员的访问和作用域

二、类的作用域

1. 类中的成员函数可互相直接调用。

2. 类中的数据成员在类中各成员函数间属“ 公共变量”。

3. 成员函数中的变量若有与类中的数据成员同名同类,则类中的数据成员被隐藏。

//----examp2_3.cpp#include <iostream.h>class Date{public: Date( ) {day=31; month=12; year=2000; } void getday( );private: int day,month,year;};void main( ){ Date myday; myday.getday( );}void Date::getday( ){ int year=1999; cout<<"1: "<<year<<"-"<<month<<"- "<<day<<"\n"; cout<<"2: "<<Date::year<<"-"<<month<<"-" <<day<<"\n";}

例 : 数据成员的作用域。

运行结果:1: 1999-12-312: 2000-12-31

三、类成员的访问

两个要点:

1. 只有本类的对象可以访问本类的公有成员 .

2. 本类对象不能直接访问本类中的私有成员 .

例 2 :对【例 1】提出的问题,用类来完成三角形面积的计算。(【例 1】给定三角形的三条边,计算三角形的面积和周长)example8_2.cpp分析:1. a 、 b 、 c 属 private, 只能通过成员函数才能访问。2. setShape() 完成对三角形边长的设置。3. isTriangle()判断三条边长是否能合法。4. area() 计算三角形的面积。5. 构造函数由系统自动调用。用于初始化数据成员的值。请注意:1. 函数 isTriangle() 和 area() 不需要参数,直接使用类中的私有数据。设计概念:1. 类的对象只需要通过发送消息来完成任务。2. 类的实现过程对用户是隐藏的。

访问函数和工具函数是一种称呼

意义:划分封装的程度1. 访问函数:对外接口函数( public 成员函数)作用:设置私有数据成员值;

读取、显示和返回私有数据成员值;进行各种类的操作;测试条件的真假等。

2. 工具函数:非接口函数( private 成员函数)作用: 支持类中其他函数的操作。

§8.5 访问函数和工具函数的意义

例 3 :实现一个销售统计问题。从键盘输入某商品每个月销售了多少件,统计该年度共销售了多少件,并计算总销售额。分析:以销售的商品作为对象; 对象的基本属性为:①价格;②每月的销售数量。 基本功能为:①输入每月的销售额; ②输出年度总销售量及总销售额; ③计算年度总销售量及总销售额。(因计算的功能不属于对象应具有的 )访问函数:

void setSell(int month,double price); // ①void printMonthSell(); // ②

工具函数:int totalAnnualSell(); // ③

程序: example8_3.cpp 思考:将工具函数改成访问函数会有什么不同?

例 4 :一个关于日期的类://----examp2_1.cpp#include <iostream.h>class Temp{public: void getday( ); void setday();private: int day,month,year;};void main( ){ Temp myday; //myday.day=12; 错误的语句 myday.getday( ); myday.setday( );}

void Temp::getday( ){ day=1;

month=1;year=1980;cout<<"1: "<<year

<<"-"<<month <<"-"<<day<<"\n";}void Temp::setday( ){ day=day+9;

month=month+9;year=year+20;cout<<"2: "<<year

<<"-"<<month <<"-"<<day<<"\n";}

运行结果: 1: 1980-1-12: 2000-10-10

点评程序例 4 :

1 .类名不明确: Temp 和 Date(日期 )关联不明。

程序中的不良之处:

2 .函数功能不明确: 函数 getday() 和函数 setday() 都可以修改私有数据成员。

设计原则:1 .类名要能反映分类的思想。2.每个函数应具有独立的功能。

例 5 :修改例 4 的程序。//----examp2_1a.cpp#include <iostream.h>class Date{public: void getday( ); void setday( );private: int day,month,year;};void main( ){ Date myday; cout<<"1:"; myday.getday(); cout<<"2:"; myday.setday(); myday.getday();}

void Date::getday( ){ cout<<year<<"-" <<month <<"-" <<day<<"\n";}void Date::setday( ){ day=day+9;

month=month+9;year=year+20;

}

运行结果:

1: 19394-5855-104592: 19414-5864-10468

无法预料的结果

点评程序例 5 :1.好的方面:类名比较清晰,函数功能比较明确。

2 .不好的方面:程序中出现了不可预料的结果,原因是由于对象的私有数据成员的值没有初始化。

设计原则:1 .任何对象的私有成员的值都应该进行初始化,以避免产生不确定的值。2 . get 函数一般不要求带参数, set 函数一般要求要带参数。

例 6 :改进例 5 的程序。//----examp2_1b.cpp#include <iostream.h>class Date{public: void getday();

void setday(int y,int m,int d);private:

int day,month,year;};void main( ){ Date myday; int yy=2000,mm=12,dd=31; myday.setday(yy,mm,dd); myday.getday(); yy=2001,mm=1,dd=1; myday.setday(yy,mm,dd); myday.getday();}

void Date::getday( ){ cout<<year<<"-" <<month<<"-" <<day<<"\n";}void Date::setday(int y,int m,int d){ day=d; month=m; year=y;}

运行结果:

1980-1-12000-10-10

点评程序例 6 :产生的新问题:必须要先调用 set 函数,对私有数据成员赋值,才能确保程序的稳定。

设计原则:1 .任何对象生成之处,就拥有初始值。2 . set 函数一般使用在程序中间,需要修改数据成员数值的时候。3.采用构造函数为对象的数据成员赋初值。

§8.6 接口和实现的分离实际上就是将类的定义与类中的函数定

义分别放在不同的文件中

4. 连接目标代码 1 和目标代码 2

P.236—— 将程序 example8_3.cpp 进行分离

1. 类的定义 < 基本名 >.h保存在

2. 类中成员函数的定义 < 基本名 >.cpp

目标代码 1

保存在

编译成

3. 主程序 ( 头文件包含类定义文件 ) < 文件名 >.cpp

目标代码 2

保存在

编译成

本章小结本章小结重点:

1. 定义一个新的数据类型:类2. 类中成员的性质 : private、 public3. 一种属于 " 类 " 的数据类型:对象4. 对象访问类中成员的权限5. 访问函数和工具函数6. 接口和实现的分离

本章练习

一、选择题

二、填空题

三、程序理解题

四、简答题

五、编程题

8.38 、 8.39 、 8.42 、 8.43