《C++面向对象程序设计导论》-从抽象到编程 课件 05 设计与实现_第1页
《C++面向对象程序设计导论》-从抽象到编程 课件 05 设计与实现_第2页
《C++面向对象程序设计导论》-从抽象到编程 课件 05 设计与实现_第3页
《C++面向对象程序设计导论》-从抽象到编程 课件 05 设计与实现_第4页
《C++面向对象程序设计导论》-从抽象到编程 课件 05 设计与实现_第5页
已阅读5页,还剩44页未读 继续免费阅读

下载本文档

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

文档简介

Josephus游戏设计《C++面向对象程序设计导论》--从抽象到编程第5章设计与实现5.1.1分析设计5.1Josephus游戏5.1.2编码实现5.1.3程序维护本节学习目标能够从具体应用场景中识别事物及其关系并抽象出类和关联(静态)能够从具体应用场景中识别事物的行为并抽象出类的方法(动态)能够使用对象图、类图、时序图等工具建立软件模型能够运用前面4章所学的知识解释分析设计的步骤和方法

Josephus游戏:一群小孩围成一圈,任意假定一个数m,从第一个小孩起,顺时针方向数数,每数到第m个小孩时,该小孩便离开。小孩不断离开,圈子不断缩小。最后剩下一个小孩便是胜利者。Josephus游戏介绍5.1.1分析设计步骤1.发现对象及其连接2.合并对象并划分职责3.抽象类及关联4.发现类的属性5.发现类的方法从具体到抽象:应用场景开始1.发现对象及其连接选择典型游戏场景描述典型游戏场景标识游戏场景中的事物及其关系图5.1典型游戏场景中的事物及其关系2.合并对象并划分职责将对象“小孩数”和“间隔数”组合到对象“游戏”将“获胜者”聚合到对象“游戏”将对象“圆圈”聚合到“游戏”每个小孩负责管理自己,承担加入、离开等职责赋予“游戏”管理“小孩数”和“间隔数”“获胜者”“圆圈”的职责图5.2对象之间的组合聚合连接3.抽象类及关联图5.3标注类别的对象及连接图5.4Josephus游戏中的类及其关联“小孩”、“游戏”和“圆圈”三类别,视为三个类“Boy”、“Jose”和“Ring”图5.4Josephus游戏中的类及其关联图5.5类中增加的属性第一步,将numOfBoys和m作为类Jose的属性。第二步,将关联对端的名称作为属性名,用于表示类之间的关联。第三步,增加与场景有关的属性。4.发现类的属性图5.6对象的职责与协作图5.7类的属性和成员函数根据Message(信息)设计成员函数5.发现类的方法练习1.发现对象及其连接2.合并对象并划分职责3.抽象类及关联4.发现类的属性5.发现类的方法在PowerDesigner15.3中重做上述分析设计过程总结及进一步学习思维:从具体到抽象(概念思维)分析设计:分析应用场景中的事物及其变迁,设计软件模型工具:对象图、类图、时序图5.1.2编码实现进一步学习第5章设计与实现5.1.1分析设计5.1Josephus游戏5.1.2编码实现5.1.3程序维护学习目标能够针对所设计的软件模型(PIM)选用恰当的实现技术建立软件的实现模型(平台相关模型,PSM)能够根据需求变化调整软件的模型并体会易维护性能够在VS2013中编程实现软件的实现模型5.1.2编码实现编码实现1.选择实现技术2.编程实现类Boy3.编程实现类Ring4.编程实现类Jose5.编写main()函数图5.9具有C++语言和链表特性的类图1.选择实现技术主要问题:如何编程实现关联?回到玩游戏的典型场景在链表上继续玩游戏图5.8典型场景中的对象及连接图5.9具有C++语言和链表特性的类图图5.7类的属性及成员函数2.编程实现类Boy图5.9具有C++语言和链表特性的类图图5.10与类Boy相关的交互过程编程实现类Boy续class

Boy{public:Boy(Boy*pPosition,intid);voidleave(Boy*pPosition);voidprint();Boy*next();protected:int

code;Boy*pNext;};#include

"Boy.h"#include

<iostream>using

namespacestd;Boy::Boy(Boy*pPosition,intid){code=id;if(!pPosition){this->pNext=this;//只有一个小孩时,自己指向自己}else{this->pNext

=pPosition->pNext;//当前小孩指向第一个小孩pPosition->pNext=this;//插入到小孩*pPosition的后面

//与上一条不能交换}}插入第1个小孩后的情况插入第2个小孩后的情况pFirst=pCurrent=new

Boy(nullptr,1);Boy*pB=pFirst;for(inti=2;i<=n;i++){pB=new

Boy(pB,i);}pPositionNULLpNextthispNextpNextpFirstpCurrentvoidBoy::leave(Boy*pPosition){

pPosition->pNext=this->pNext;cout<<"离开:"

<<code<<endl;}voidBoy::print(){cout<<"Id:"<<code;}Boy*Boy::next(){return

pNext;}thispPosition一个小孩离开(以4个小孩为例演示)3.编程实现类Ring图5.9具有C++语言和链表特性的类图图5.13与类Ring相关的交互过程#include

"Ring.h"Ring::Ring(intn){pFirst=pCurrent=new

Boy(nullptr,1);Boy*pB=pFirst;for(inti=2;i<=n;i++){pB=new

Boy(pB,i);}}#include

"Boy.h"class

Ring{public:Ring();Ring(intn);~Ring();Boy

getWinner(intm);private:voidcountUpTo(intm);Boy*pFirst;Boy*pCurrent;};Boy

Ring::getWinner(intm){//数小孩while

(pCurrent!=pCurrent->next()){ countUpTo(m);//往下数m个小孩,数到的小孩离开}//返回获胜者Boywin(*pCurrent);

//另外创建(复制)一个Boy对象delete

pCurrent;returnwin;}voidRing::countUpTo(intm){//往下数m个小孩Boy*pLast;for(inti=m;i>1;i--){pLast=pCurrent;pCurrent=pCurrent->next();}//数到的小孩离开

pCurrent->leave(pLast);//当前从圆圈中离开,pLast指向前面的小孩

deletepCurrent;//删除当前小孩pCurrent=pLast->next();//当前小孩是上一个小孩的下一个}Ring::~Ring(){}编程实现类Ring续pCurrentpLast一个小孩离开(以4个小孩为例演示)4.编程实现类Jose#include

"Ring.h"class

Jose{public:Jose(intboys,intinterval);~Jose();Boy

gameBegin();private:int

numOfBoys;int

m;Ring*ring;Boy*win;};#include

"Jose.h"Jose::Jose(intboys,intinterval){numOfBoys=boys;m=interval;ring=new

Ring(boys);win=nullptr;}Jose::~Jose(){delete

ring;delete

win;}Boy

Jose::gameBegin(){if(!win)win=new

Boy(ring->getWinner(m));return*win;}5.编写main()函数#include

"Jose.h"#include

<iostream>using

namespacestd;intmain(){Josejs1(7,3);js1.gameBegin().print();intm,n;cout<<endl<<"请输出小孩数和间隔数......"

<<endl;cin>>n>>m;Josejs2(n,m);js2.gameBegin().print();cout<<endl<<"现在宣布"

<<endl<<"第一场获胜者是:"

<<endl;js1.gameBegin().print();cout<<endl<<"第二场获胜者是:"

<<endl;js2.gameBegin().print();}离开:3离开:6离开:2离开:7离开:5离开:1Id:4请输出小孩数和间隔数......104离开:4离开:8离开:2离开:7离开:3离开:10离开:9离开:1离开:6Id:5现在宣布第一场获胜者是:Id:4第二场获胜者是:Id:55.1.3程序维护增加类Person,增加类Boy到类Person的关系Boy(Boy*pPosition,intid,Person*ps);Ring(intn,Person*ps[]);Jose(intboys,intinterval,Person*ps[]);图5.14增加继承关系后的类图图5.15增加小孩信息后的对象职责及其协作Boy::Boy(Boy*pPosition,intid,Personps):Person(ps){ code=id;

if(!pPosition){

this->pNext=this; //只有一个小孩时,自己指向自己 }

else{

this->pNext=pPosition->pNext; pPosition->pNext=this; }}Ring::Ring(intn,Person*ps[]){ pFirst=pCurrent=newBoy(NULL,1,*ps[1]); Boy*pB=pFirst;

for(inti=2;i<=n;i++){ pB=newBoy(pB,i,*ps[i]); }}Jose::Jose(intboys,intinterval,Person*ps[]){ numOfBoys=boys; m=interval; ring=newRing(boys,*ps); win=NULL;}voidBoy::print(){ cout<<"Id:"<<code; Person::print();}修改实现代码练习VS2013上编辑调试【例5.1-5.5】中的代码1.选择实现技术2.编程实现类Boy3.编程实现类Ring4.编程实现类Jose5.编写main()函数6.增加类Person并修改代码总结及进一步学习设计:选用编程实现技术细化软件模型编码:按照软件模型声明类,编码实现类的成员函数维护:调整软件模型,修改程序代码5.2矩阵计算进一步学习5.2.1矩阵和向量的乘法5.2矩阵计算5.2.2使用友元提高运行速度第5章设计与实现学习目标能够识别数学模型中的关键因素(矩阵及运算),设计出软件模型能够选用适当的编程技术实现软件模型能够使用友元提高代码的运行效率5.2.1矩阵和向量的乘法存储计算

Amn×Vn=(bi)m

图5.16矩阵和向量相乘【例5.6】矩阵与向量的乘法//Vector.hclass

Vector{public:

int&Elem(inti); Vector(intn); Vector(const

Vector&oldVector); ~Vector();

voidprint(void);

intgetN(void);private:

intn;

int*v;};//Vector.cpp#include

"Vector.h"#include

<iostream>using

namespacestd;

int&Vector::Elem(int

i){

if(i<n)

returnv[i];

else cout<<"超标越界!!";}Vector::Vector(int

n){

Vector::n=n; v=new

int[n];}Vector::~Vector(){

deletev;}void

Vector::print(){ cout<<v[0];

for(inti=1;i<n;i++) cout<<"\t"<<v[i];}int

Vector::getN(){

returnn;}Vector::Vector(const

Vector&oldVector){ n=oldVector.n; v=new

int[n];

for(inti=0;i<n;i++){ v[i]=oldVector.v[i]; }}Matrix代码//Matrix.hclass

Matrix{public:

int&Elem(inti,intj); Matrix(intm,intn); Matrix(const

Matrix&oldMatrix); ~Matrix();

voidprint();

intgetM();

intgetN();private:

intm;

intn;

int*Mat;};

//Matrix.cpp#include

"Matrix.h"#include

<iostream>using

namespacestd;

int&Matrix::Elem(int

i,int

j){

if(i<m&&j<n)

returnMat[i*n+j];//计算第i行第j列元素的位置

else cout<<"超标越界!!";}Matrix::Matrix(int

m,int

n){

Matrix::m=m;

Matrix::n=n; Mat=new

int[m*n];}Matrix::~Matrix(){

delete[](int*)Mat;}void

Matrix::print(){

for(inti=0;i<m;i++){ cout<<Mat[i*n+0];

for(intj=1;j<n;j++){ cout<<"\t"<<Mat[i*n+j]; } cout<<endl; }}int

Matrix::getM(){

returnm;}int

Matrix::getN(){

returnn;}Matrix::Matrix(const

Matrix&oldMatrix){ m=oldMatrix.m; n=oldMatrix.n; Mat=new

int[m*n];

for(inti=0;i<m*n;i++) Mat[i]=oldMatrix.Mat[i];}【例5.6】矩阵与向量的乘法#include

"Matrix.h"#include

"Vector.h"#include

<iostream>using

namespacestd;

VectorMultiply(Matrix&mat,Vector&vec){

//省略检查行列的代码

Vectorc(mat.getM());

for(inti=0;i<mat.getM();i++){

c.Elem(i)=0;

for(intj=0;j<mat.getN();j++){

c.Elem(i)+=mat.Elem(i,j)*vec.Elem(j); } }

returnc;}voidmain(){

intm=3,n=4;

cout<<"矩阵:"<<endl;

Matrixa(m,n);

for(inti=0;i<m;i++){

for(intj=0;j<n;j++){ a.Elem(i,j)=(i+1)*10+j+1; } } a.print();

cout<<endl<<"向量:"<<endl;

Vectorv(n);

for(inti=0;i<n;i++){ v.Elem(i)=(i+1)*2; } v.print(); cout<<endl<<"矩阵×向量:"<<endl; Multiply(a,v).print();}

Amn×Vn=(bi)m5.2.2使用友元提高运行速度

封装能够提高程序的安全性和可维护性,但也会降低程序的运行速度。面向对象程序设计中,借鉴日常中的“朋友”提出了友元(friend)的概念,可以将一些函数或类指定为一个类的友元,并按照“朋友”值得相信的常识,允许这些函数或类直接访问其私有的或保护的成员。【例5.7】将普通函数声明为友元classVector;classMatrix{

friendVectorMultiply(Matrix&mat,Vector&vec); //声明友元函数 //以下代码省略};

classMatrix;classVector{

friendVectorMultiply(Matrix&,Vector&); //声明友元函数 //以下代码省略};

好处:Multiply()函数中就可直接访问类Vector和Matrix的数据成员直接访问矩阵和向量中的元素//未使用友元代码VectorMultiply(Matrix&mat,Vector&vec){

//省略检查行列的代码

Vectorc(mat.getM());

for(inti=0;i<mat.getM();i++){

c.Elem(i)

=0;

for(intj=0;j<mat.getN();j++){

c.Elem(i)+=mat.Elem(i,j)*vec.Elem(j); } }

returnc;}//使用友元代码VectorMultiply(Matrix&mat,Vector&vec){ //省略检查行列的代码

Vectorc(mat.m); for(inti=0;i<mat.m;i++){

c.v[i]

=0; for(intj=0;j<mat.n;j++){

c.v[i]+=mat.Mat[i*mat.n+j]*vec.v[j]; } } returnc;}破坏了封装,提高了运行效率!!【例5.8】将成员函数声明为友元按照“A乘以B”的习惯m.Multiply(v).print();图5.17使用成员函数实现乘法运算例5.8示例代码#include

"Matrix.h"class

Vector{

friend

VectorMatrix::Multiply(Vector&vec);//将类Matrix的成员函数声明友元

//friendclassMatrix;//声明友元类

//以下代码省略};VectorMatrix::Multiply(Vector&vec){

//省略检查行列的代码

Vectorc(m);

for(inti=0;i<m;i++){ c.v[i]=0;

for(intj=0;j<n;j++){

c.v[i]+=Mat[i*n+j]*vec.v[j]; } }

returnc;}请参考例【5.6】,编写调试通过练习1.根据图5.16所示软件模型采用普通函数实现矩阵乘法2.根据图5.17所示结合友元技术采用成员方法实现矩阵乘法VS2013上编辑调试【例5.6-5.8】中的代码图5.16矩阵和向量相乘图5.17使用成员函数实现乘法运算总结及进一步学习设计:根据数学模型设计软件模型的方法编码:根据软件模型编写程序代码的方法优化:使用友元提高代码运行速度的方法5.3异常处理进一步学习5.3.1异常分类和错误定义5.3异常处理5.3.2识别异常和抛出错误第5章设计与实现5.3.3捕获异常并处理错误学习目标能够运用面向对象知识解释运行环境中的异常及其层次关系能够使用C++编写定义、抛出、捕获和处理异常的代码能够针对一个具体场景描述抛出异常和捕获异常的过程5.3.1异常分类和错误定义使用类描述异常的类别使用继承关系描述层次关系定义错误编号定义错误信息分级处理机制软件=程序+数据+文档+运行环境图5.18异常及其分类例5.9示例代码//MyErr.hclass

MyErr{public: MyErr(interrNo,const

char*msg); MyErr(const

MyErr&oldMyErr); myStringgetErrMsg();

intgetErrNo();protected: myStringerrMsg;

interrNo;};class

SysErr:public

MyErr{public: SysErr(intsysNo,const

char*msg); SysErr(const

SysErr&oldSysErr);

intgetSysErrNo();protected:

intsysErrNo;};class

FileErr:public

SysErr{public: FileErr(const

char*msg);};class

MemErr:public

SysErr{public: MemErr(const

char*msg);};class

LogicErr:public

MyErr{public: LogicErr(intlogErrNo,const

char*msg); LogicErr(const

LogicErr&oldLogicErr);

intgetLogErrNo(void);protected:

intlogErrNo;};class

MatErr:public

LogicErr{public: MatErr(const

char*msg);};class

VecErr:public

LogicErr{public: VecErr(const

char*msg);};class

MulErr:public

LogicErr{public: MulErr(const

char*msg);};

//MyErr.cpp#include

"myString.h"#include

"MyErr.h"

MyErr::MyErr(int

errNo,const

char*msg):errMsg(msg){

MyErr::errNo=errNo;}MyErr::MyErr(const

MyErr&oldMyErr):errMsg(oldMyErr.errMsg){ errNo=oldMyErr.errNo;}myStringMyErr::getErrMsg(){

returnerrMsg;}int

MyErr::getErrNo(){

returnerrNo;}

SysErr::SysErr(int

sysNo,const

char*msg):MyErr(1,msg){ sysErrNo=sysNo;}SysErr::SysErr(const

SysErr&oldSysErr):MyErr(oldSysErr.errNo,oldSysErr.errMsg.getString()){ sysErrNo=oldSysErr.sysErrNo;}int

SysErr::getSysErrNo(){

returnsysErrNo;}FileErr::FileErr(const

char*msg):SysErr(1,msg){}MemErr::MemErr(const

char*msg):SysErr(2,msg){}LogicErr::LogicErr(int

logErrNo,const

char*msg):MyErr(2,msg){

LogicErr::logErrNo=logErrNo;}LogicErr::LogicErr(const

LogicErr&oldLogicErr):MyErr(oldLogicErr.errNo,oldLogicErr.errMsg.getString()){ logErrNo=oldLogicErr.logErrNo;}int

LogicErr::getLogErrNo(){

returnlogErrNo;}MatErr::MatErr(const

char*msg):LogicErr(1,msg){}VecErr::VecErr(const

char*msg):LogicErr(2,msg){}MulErr::MulErr(const

char*msg):LogicErr(3,msg){}5.3.2识别异常和抛出错误#include

"MyErr.h"#include

"Vector.h"#include

<iostream>using

namespacestd;

int&Vector::Elem(int

i){

if(i<n)

returnv[i];

else

throwVecErr("向量中数组下标越界!");}Vector::Vector(int

n){ Vector::n=n; v=new

int[n];

if(!v)

throwMemErr("向量中申请内存失败!");}Vector::Vector(constVector&oldVector){ n=oldVector.n; v=new

int[n];

if(!v)

throwMemErr("向量中申请内存失败!");

//省略下面代码}#include

"MyErr.h"#include

"Matrix.h"#include

"Vector.h"#include

<iostream>using

namespacestd;

int&Matrix::Elem(int

i,int

j){

if(i<m*n)

returnMat[i*n+j];

else

throwMatErr("矩阵中数组下标越界!");}Matrix::Matrix(int

m,int

n){ Matrix::m=m; Matrix::n=n; Mat=new

int[m*n];

if(!Mat)

throwMemErr("矩阵中申请内存失败!");}Matrix::Matrix(constMatrix&oldMatrix){ m=oldMatrix.m; n=oldMatrix.n; Mat=new

int[m*n];

if(!Mat)

throwMemErr("矩阵中申请内存失败!");

for(inti=0;i<m*n;i++) Mat[i]=oldMatrix.Mat[i];}

5.3.3捕获异常并处理错误#include

"myString.h"#include

"MyErr.h"#include

"Matrix.h"#include

"Vector.h"#include

<iostream>using

namespacestd;

VectorMultiply(Matrix&mat,Vector&vec){

//检查行列的代码

if(mat.getN()!=vec.getN())

throwMatErr("矩阵和向量的行列不符合相乘条件!

温馨提示

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

评论

0/150

提交评论