《类与对象的定义.ppt》由会员分享,可在线阅读,更多相关《类与对象的定义.ppt(48页珍藏版)》请在三一办公上搜索。
1、面向对象程序设计,清华大学 计算机科学与技术系徐明星、黄震春、姚海龙2012春VI-A017,III-1204,1,OOP从认识“对象”开始.,对象,是对现实世界中实际存在事物的抽象描述,它可以是有形的,也可以是无形的(1)对象具有自己的静态特征和动态特征静态特征 可以用某种数据来描述的特征;动态特征 对象表现的行为或具有的功能。(2)对象是由一组属性数据和对这些数据进行特定操作的一组服务所构成的“结合体”(概念)。封装=属性/数据,服务/函数,2,数据,到底是什么?看看数学家怎么说(1),在数学上,“数据”不仅有值,而且限定了在值上的操作规范(约束)和性质。程序设计语言中的“类型”的概念与此
2、相似,如“整数相除得整数”:3/4=0。,数据,到底是什么?看看数学家怎么说(2),数据,到底是什么?看看程序员怎么说,类型 数据的存储与表示+数据支持的操作,封装的“装”数据抽象,对象从程序语言角度看一个独立的、有约束的的实体,既有自己的状态记忆(数据成员),又有活动能力(函数成员)。封装使程序在描述数据的同时,能描述数据参与的运算和提供的功能,实质是引入了一个新的类型。数据+函数从设计思想上看封装(数据+函数)是OOP的基本特征有计算能力的数据,是对原先仅表示数值的“数据”这个概念的更抽象认识,即“抽象的数据”。,6,用结构struct将变量定义(属性)和函数定义(操作)包含到一起,使属性
3、与操作不仅在逻辑上是一个整体,而且在物理上也是一个整体。如下例中数据Name与操作show():文件前后的条件编译选项,是为了允许头文件被重复包含。,#ifndef _STUDENT_H_#define _STUDENT_H_struct Student char Name20;void show();#endif/_STUDENT_H_,#ifndef _PERSON_H_#define _PERSON_H_struct Person char Name20;void show();#endif/_PERSON_H_,7,C+如何进行“封装”?,#include person.h#inclu
4、de using namespace std;void Person:show()cout Name:Name endl;/person.cpp,#include student.h#include using namespace std;void Student:show()cout Name:Name endl;/student.cpp,8,/TEST-EX1.cpp 包含头文件时,编译开发环境提供的库头文件在后/g+test-ex1.cpp person.cpp student.cpp#include person.h/person struct#include student.h/st
5、udent struct#include/strcpyint main()Person manA,manB;strcpy(manA.Name,Zhang San);strcpy(manB.Name,Li Si);manA.show();manB.show();Student s1,s2;/变量到使用前才定义它们strcpy(s1.Name,Wang Wu);strcpy(s2.Name,Zhao Liu);s1.show();s2.show();return 0;,9,电子计价器,10,电子计价器1.0(FOP版),11,电子计价器2.0(OOP版)设计思路与步骤,确定属性保存什么数据苹果的价
6、格,香蕉的价格苹果的重量,香蕉的重量总钱数确定服务提供什么功能(函数)设置价格(苹果香蕉分开设?一起设?)设置重量(苹果香蕉分开设?一起设?)计算总价显示总价(指计价器显示屏上显示的总价),12,13,分析原算法的流程,计算任务如何执行(完成)?发送消息给对象,int main()calc wxr_calc2;wxr_calc2.set_prices(3.5,4.2);wxr_calc2.set_weights();wxr_calc2.how_much();return 0;,14,消息,对象,向对象发消息,要求完成指定的任务,#include/预编译命令using namespace std
7、;struct calc/计价器中存储的数据 float ApplePrice,BananaPrice;float AppleWeight,BananaWeight;float Total;/计价器提供的操作方法与功能 void set_prices(float,float);void set_weights();void how_much();,代码实现,15,代码实现,void calc:set_prices(float a,float b)ApplePrice=a;BananaPrice=b;void calc:set_weights()coutAppleWeight;/输入苹果重量 c
8、outBananaWeight;/输入香蕉重量void calc:how_much()Total=ApplePrice*AppleWeight+BananaPrice*BananaWeight;/计算应付款 cout 应付款 Total endl;/输出应付款,16,电子计价器3.0(OOP增强版),思考题如果希望计价功能更灵活,应该如何设计?有多种商品,而不是只有苹果和香蕉能随意购买,而不是每种都要买加强小摊贩管理价格只能一次性设置销售信息记录网上水果店(阿里巴巴)另外,前面的示例代码有没有隐患?,17,谁做的好事?(OOP版),18,“面向对象”的课堂新游戏,.,19,领取各自的台词根据自
9、己的台词,判断“校长”的猜想,对象在哪里?,每个游戏参与者(学生)对象的属性(数据/静态特征/变量)游戏活动中设定的台词(所说的话)对象的服务(操作/动态特征/函数)根据校长提出的某个“假设答案”,给出判断,回答手中的要说的“台词”是真话,还是假话。,20,int main()person four_stu4;for(int i=0;i4;i+)cout Please input words of student i+1:;four_stui.get_words();/各人拿到自己的“台词”for(char ans=A;ans=D;ans+)int count=0;for(int i=0;i4
10、;i+)/各自判断台词是否为真话 if(four_stui.check_ans(ans)count+;/“校长”对真话进行计数if(count=3)cout This man is ans endl;break;return 0;,代码实现,21,#include using namespace std;struct person char words10;void get_words();bool check_ans(char ans);void person:get_words()cin words;/X=A,X#Abool person:check_ans(char ans)if(wor
11、ds1=#)return ans!=words2;elsereturn ans=words2;,代码实现,22,刚才,“校长”在哪里?,思考题若要在前面的程序中,要增加一个表示“校长”的对象,那么,该对象有什么属性?该对象有什么操作?如何修改现有程序,以实现上述设计设想?,23,更精细地刻画“对象”,属性+服务 对象封装的第一层涵义:数据抽象直观反映了客观世界中的概念简化了对复杂世界的分析与认知形成了不同对象之间的“边界”(正是这些边界,才使不同对象可以区别开)但还不够精细比如:有些属性、服务其实是只对内的,并不对外,这些性质差异目前没有反映出来!,24,public 含义:对象允许外界对这些
12、属性(数据成员)与功能(函数成员)进行自由的访问private 含义:对象禁止外界对这些属性与功能进行访问(发消息或读写数据)实现控制的途径:借助编译器,在代码编译阶段检查访问是否“被允许”。不允许语句的会报编译错!“权限控制”是手段,目标是体现“封装”的第二层涵义“信息隐藏”,封装的“封”权限控制,25,封装的“封”接口概念,类的接口能通过对象来访问到的部分。接口是程序设计中一个非常重要和关键的概念:使用类时,能避开不相关的细节 思路更清晰这实际上是方便了别人(使用类的编程人员)-接口使他们可以很容易知道类的哪些部分对他们是重要的,哪些是不重要可以忽略的设计类时,能自由变更具体实现 修改更方
13、便这实际上是为了方便我们(设计和实现类的人)-接口使我们可以很容易修改具体实现(允许我们犯错误),而不会影响最终的功能,26,class:水到渠成的名正言顺,有了封装之后,struct被大地增强了:通过数据抽象(数据+函数),产生了既有数据又有操作的新数据类型通过信息隐藏(权限控制),规定了新类型对外的接口,间接地“约束和规范”了对类的使用,进而使得分离具体实现与接口成为可能为了与传统struct区别开,突出反映封装概念中体现的重要思想,引入新关键字class,27,旋转方阵(OOP版),28,要求矩阵大小任意,尺寸在运行时输入,测试驱动的软件开发方法(TDD),能更直观和准确地帮助理解对类的
14、接口需求避免了过早地纠缠于类的实现细节当程序代码最终被完全实现出来时,亦同时完成了对代码的测试,所以不必担心算法错误要求以最高效率解决各种错误(如编译错误、结果错误、运行崩溃等),程序员在编程时能更加专注,29,高效实现的策略测试驱动,在给出类的具体实现前,应先写出测试类的代码(这样当然是不够的,会出编译错误)。根据编译错误的提示,以最高效率、最小代价“消除”编译错误。(这样当然还是不够的,会出结果错误,甚至运行崩溃)。根据结果错误的现象,完善或改进算法实现,即给出成员函数的正确定义。,30,设计思路:基于TDD,从上到下期待新类如何被使用?,int main()matrix obj;cout
15、 size;obj.init(size);/生成N*N矩阵 obj.fill();/按规则完成数字填充 obj.print();/输出填充结果 obj.clear();/释放矩阵内存 return 0;,31,设计思考:对象?接口?,矩阵对象(类)的初步设想属性(数据成员):二维动态数组、大小 服务(函数成员):填充数字、输出 期待提供的类的接口void init(int size);/初始化void fill();/填充void print();/输出void clear();/释放内存空间,32,代码实现V1,#include#include using namespace std;cla
16、ss matrix int N;int*M;public:void init(int size);/create a matrix void clear();/release memory void fill();/fill all numbers in matrix void print();/output matrix;,33,void matrix:init(int size)N=size;M=new int*N;/在二维数据中,先分配指向各行的指针 for(int r=0;rN;r+)/r means row Mr=new intN;/再为各行分配列空间memset(Mr,0,size
17、of(int)*N);/矩阵清零,表示无数字 void matrix:clear()for(int r=0;rN;r+)delete Mr;delete M;,34,二维动态数组的生成方法(套路),二维动态数组的清除方法(套路),代码实现V1,void matrix:print()/先行后列次序依次输出各行上的数字 for(int r=0;rN;r+)/row for(int c=0;cN;c+)/col cout setw(3)Mrc;cout endl;void matrix:fill()for(int num=1;num=N*N;num+)place(num);/将num放到矩阵中,35
18、,代码实现V1,没有定义该函数,会出编译错误,/为matrix类新增一个成员函数,以便让程序编译通过void matrix:place(int num),36,代码实现V1,函数体是空的,程序会出“结果错误”,相应的类定义也需要改动,见下页,代码实现V2,#include#include using namespace std;class matrix int N;int*M;void place(int num);public:void init(int size);/create a matrix void clear();/release memory void fill();/fill
19、 all numbers in matrix void print();/output matrix;,37,新增,根据算法实现,还需要?,函数成员void place(num):对待填写的数值,计算它在矩阵中的位置,并填写到矩阵中填写思路:模拟人在迷宫中根据指示前进在必要时,改变前进的方向数据成员:当前填充的前进方向char dir;/用4个字符DRUL代表前进方向已填充的最后位置(行、列)int row,col;,38,#include#include/setwusing namespace std;class matrix int N;int*M;int row,col;/last lo
20、cation char dir;/D,R,U,L void place(int num);/put num in matrixpublic:void init(int size);/create a matrix void clear();/release memory void fill();/fill all numbers in matrix void print();/output matrix;,39,代码实现V3,void matrix:init(int size)N=size;M=new int*N;/在二维数据中,先分配指向各行的指针 for(int r=0;rN;r+)/r
21、means row Mr=new intN;/再为各行分配列空间memset(Mr,0,sizeof(int)*N);/矩阵清零,表示无数字/设定起始位置,起始方向 col=0;row=-1;/virtual previous position dir=D;/init direction,40,代码实现V3,41,void matrix:place(int num)/?,代码实现V3,void matrix:place(int num)/STEP 1:先根据前一位置、方向,/以及摆放规则(DRUL)确定下一个摆放数据的位置 switch(dir)case D:/先保证row在合法范围内,/再考
22、虑该处是否已有数字(是否为0)if(row N-1,42,代码实现V3,case R:if(col 0,43,代码实现V3,case L:if(col 0,44,代码实现V3,深入思考自己给自己出题:,如果旋转方向从DRUL(逆时针)变成RDLU(顺时针),则程序应该如何修改?如果希望两种旋转方向的填充策略都能支持,程序又应该如何修改?更进一步地,如果希望扩展到其他类型的填充次序,如蛇形、Z字形、U字形.等,应该如何修改类的对外接口与具体实现?,45,W02知识内容小结,46,封装OOP的基础,有两个涵义:数据抽象和信息隐藏。数据抽象界定了“对象”的内涵:有哪些属性、有什么功能。信息隐藏划定了“对象”的接口:什么是公开可见的,什么是不可访问操作的。找出程序中涉及的所有“数据/属性/状态”和“函数/性质/操作”,将概念上一体的数据与函数在物理上放置到一起。基于TDD的开发策略。,W03语法知识自学要求,47,构造函数、析构函数、默认构造函数(缺省构造函数)带参数的对象定义对象数组的定义与注意事项(要求类有默认构造函数)函数重载函数的缺省参数(默认参数),本周课后有作业,要求学生互评,结束,48,