面向对象课程设计任务及代码
目录
一.任务一 ............................................................................................................... 1 1.1任务介绍及小组成员任务分配 . ................................................................. 1 1.2设计思想及主要流程图 . ............................................................................. 1 1.3主要程序清单 .............................................................................................. 2 1.4运行结果及分析 . ......................................................................................... 3 2.1任务介绍及小组成员任务分配 . ................................................................. 3 2.2设计思想及主要流程图 . ............................................................................. 4 2.3主要程序清单 .............................................................................................. 5 2.4运行结果及分析 . ......................................................................................... 6 3.1任务介绍及小组成员任务分配 . ................................................................. 7 3.2设计思想及主要流程图 . ............................................................................. 7 3.3主要程序清单 .............................................................................................. 8 3.4运行结果及分析 . ....................................................................................... 11 二.任务二 ............................................................................................................. 12 1任务介绍及小组成员任务分配 . ................................................................... 12 2设计思想及主要流程图 . ............................................................................... 12 3主要程序清单 ................................................................................................ 18 4. 运行结果及分析 ............................................................................................ 22 三、收获、体会及建议: . .................................................................................... 23
一.任务一
1.1任务介绍及小组成员任务分配 任务介绍
根据输出设计类
设计类就是根据数据封装的要求,抽象出适合的类。
有如下测试程序和测试程序的输出结果,要求设计类Welcome 。 void main() {
Welcome we;
Welcome you(we); you.Display();
you.Set(“Thank you.”); cout
you.talk(); you.Display();
}
测试程序的输出结果如下: Welcome!
Thank you.
输入:How about you? 输出:How about you? 输入:Fine,thank you. 输出:Fine,thank you. 输入:OK All right Goodbye! OK
Goodbye! Goodbye!
设计类Welcome 的原则
1)在头文件Cpp1.h 中声明类 2)在Cpp1.cpp 中实现类
3)使用内联函数定义Display()函数1.2设计思想及主要流程图 设计思路
该题要求根据主函数设计类且已给出运行结果。首先要分析一下主函数,了解其意义之后再根据主函数中的Welcome we;Welcome you(me);结合任务中所给的测试程序的输出结果,定义Welcome 类,输出Welcome! 只有输入为0K 时,才会输出 All right Goodbye! OK
否则输入什么输出什么,所以在这里定义一个函数talk, 并且用do-while 结构来实现循环。发现main 函数中用了两次构造函数,最后输出了两次Goodbye! 所以这里想到了析构函数。 主要流程图
1.3主要程序清单
#include #include using namespace std;
class Welcome {
public :
Welcome() { Set("Welcome!"); } ~Welcome()
{ Set("Goodbye!"); Display(); }
Welcome(Welcome & x) { Set(x.Get()); } void Display()
{ cout
{ strcpy(sentence, s); }
char *Get() { return sentence; } void talk();
private:
char sentence[64]; };
void Welcome::talk()
{
do {
cout
if (strcmp(sentence, "OK") == 0) {
cout
else { cout
}
} while(1); }
void main() {
Welcome we;
Welcome you(we);
you.Display();
you.Set("Thank you."); cout
you.talk();
you.Display();}
分析:构造函数Welcome 初始化将" Welcome!" 赋给Set 函数,再通过Display 函数输出。void
Set(char *s) { strcpy(sentence, s); }将s 赋给sentence ,再通过Display 函数输出sentence, 也就是"Thank you." 。然后是进行talk 函数,先输出" 输入:" 再输入How about you? 因为sentence 不是OK 所以再输出" 输入:" 再输入Fine,thank you.又因为sentence 不是OK 所以输出" 输入:" 再输入OK 接着输出"All right!""Goodbye!" 循环结束。然后Display 函数输出sentence 也就是OK ,最后是析构函数,输出"Goodbye!" 再Display 函数输出"Goodbye!" 。
2.1任务介绍及小组成员任务分配 任务介绍
使用类改写程序编写一个求方程ax 2+bx +c =0的根的程序,用三个函数分别求当b 2+4ac 大于零、等于零和小于零时方程的根。要求从主函数输入a 、b 、c 的值并输出结果。使用面向过程的解法一般是把变量设为double 型,适用库函数cmath 进行计算。参考程序如下:
请注意:使用面向对象的方法解决这个问题,首先要从解一元二次方程出发,抽象一个代表一元二次方程的类。为了使用这个类,必须根据要结局的问题,为这个类设计合适的数据成员和成员函数。
2.2设计思路及主要流程图 设计思路
该题要求是使用类改写程序,用三个函数分别求当b 2+4ac 大于零、等于零和小于零时方程的根。所以要改写该程序,首先要建立一个类fun ,然后在类中建立三个公用成员函数void GTzero(),void EQzero()和void LTzero()来求b 2+4ac 大于零、等于零和小于零时方程的根,再建立一个公用成员函数void set()来输入方程系数a,b,c ,之后再建立公用数据成员d 和私有数据成员b,c,x1,x2,p,q, 在类外分别对公用成员函数void GTzero(),void EQzero(),void LTzero()和void set()
进行定义,最后主函数可根据题目要求定义
一个类的对象t, 再对类内的一些成员进行调用,其顺序可以是,先输出“输入方程系数a,b,c ”来提醒用户输入数据,再调用t.set()来输入a,b,c ,之后可运用if 语句再将t.d 分为大于零,等于零和小于零的情况,分别调用 t.GTzero(),t.EQzero()和t.LTzero()。 主要流程图
2.3主要程序清单#include using namespace std; #include
class fun
5
{public: void GTzero();
cout
double a; double b; double c; double x1;
double x2; double p; double q; };
void fun::GTzero() {
x1=(-b+sqrt(d))/(2*a); x2=(-b-sqrt(d))/(2*a);
cout
void fun::EQzero() {
x1=x2=(-b)/(2*a);
cout
void fun::LTzero() {
p=(-b)/(2*a);
q=sqrt(-d)/(2*a);
cout
}
void fun::set() {
cin>>a; cin>>b; cin>>c;
d=b*b-4*a*c; cout
cout
} fun t;
void main() {
cout0) {
t.GTzero(); }
if(t.d==0) {
t.EQzero(); }
else if(t.d
t.LTzero();
}
}
6
分析
当用户输入方程系数a,b,c 后,程序会通过void set()成员函数对a,b,c 进行读入对d=b*b-4*a*c进行计算和输出,如果d0,则主函数则会调用成员函数void LTzero(),再输出实根x1,x2的值。
3.1任务介绍及小组成员任务分配 任务介绍
使用包含(聚合)和派生设计新类
(1)使用包含的方法,编写一个点类Point 和线段类Line ,演示构造函数、复制构造函数、析构函数作用及其调用顺序;
(2)使用派生的方法,编写一个点类Point ,然后由它派生线段类,并演示构造函数、复制构造函数、析构函数作用及其调用顺序。 3.2设计思想及主要流程图 1.3.1设计思路 使用包含的方法
先编写一个点类Point, 在类中声明构造函数和析构函数,再建立Distance 函数,题目中没有要求函数的输出值,定义函数输出为计算点到原点o 的距离。然后编写线类Line ,同样声明构造函数和析构函数,建立Display 函数计算两点间的距离,特别注意Line 构造函数的对象是两个Point 类,实现了类Line 对类Point 的包含。在main 函数中声明两个Point 类a 、b, 用类Line 包含已经定义的类Point ,最后调用相应的函数。 1.3.1主要流程图
1.3.2设计思路
使用派生类的方法
同包含先编写一个点类Point, 在类中声明构造函数和析构函数,再建立Distance 函数题目中没有要求,输出计算点到原点o 的距离。然后编写派生线类Line 对Point 类进行公有继承,同样声明构造函数和析构函数,建立Display 函数计算两点间的距离。在main 函数中声明两个Point 类a 、b, 实现类Line 对类Point 中对象的继承,最后调用相应的函数。
1.3.2主要流程图
3.3主要程序清单1.3.1
#include #include using namespace std;
class Point {
public:
Point(double px=0, double py=0):x(px), y(py){}
~Point(){cout
double Distance(Point &point); double x, y; };
double Point::Distance(Point &point) {
double t1, t2; t1 = point.x; t2 = point.y;
return sqrt(t1*t1+t2*t2); }
class Line {
public:
Line(Point &point1,Point &point2); double Display(Line &line); double x, y;
~Line(){cout
Line::Line(Point &point1,Point &point2)
{x = point1.x - point2.x; y = point1.y - point2.y;
1.3.2
#include #include
using namespace std;
class Point {
public:
Point(double px=0, double py=0){x = px; y = py;};
double Distance(Point &point); double x, y;
~Point(){cout
}
double Line::Display(Line &line) {
return sqrt(x*x+y*y); }
void main() {
Point a,b;
cout>a.x>>a.y;
cout>b.x >>b.y;
coutcout
cout
double Point::Distance(Point &point) {
x = point.x ; y = point.y ;
return sqrt(x*x+y*y);
}
class Line:public Point {
private: Point a,b; public:
Line(double x1, double y1, double x2,
double y2):a(x1,y1),b(x2,y2){} double Display();
~Line(){cout
double Line::Display() {
double x,y; x = b.x - a.x; y = b.y - a.y;
return sqrt(x*x+y*y); }
void main()
3.4运行结果及分析
1.3.1运行结果
1.3.1分析
首先先定义两个Point 类a 、b ,得到用户输入的a 、b 的坐标,这里调用了两次Point 类的构造函数,然后调用Distance 函数分别计算a 、b 到o 点的距离。再调用Line 类的构造函数,由于Line 类已经包含了Point 类,在调用Line 类的构造函数时就不用再对其包含的Point 类再构造,只用对整个Line 类进行构造,然后用Display 函数计算a 、b 两点的长度。这里一共调用了三次构造函数,所以析构函数也调用了三次,根据先构造的后析构,后构造的先析构这个规则,所以析构函数的调用顺序与构造函数的调用顺序相反。得到如图所示结果。
{
Point a,b;
cout>a.x>>a.y;
cout>b.x>>b.y;
coutcout
cout
1.3.2运行结果
1.3.2分析
首先同上先定义两个Point 类a 、b ,得到用户输入的a 、b 的坐标,这里调用了两次Point 类的构造函数,然后调用Distance 函数分别计算a 、b 到o 点的距离。再调用Line 类的构造函数,看Line 的构造函数: Line(double x1, double y1, double x2, double y2):a(x1,y1),b(x2,y2){}
由于派生类Line 是对Point 类的公有继承,在调用Line 类的构造函数时顺带初始化了类Point 的两个对象a 和b ,那么它肯定会
调用类Point 的构造函数,而且会调用两次, 由于Point 类的对象赋了初值,那么在调用它的构造函数之前会调用默认值的构造函数,所以这里一共调用了三次构造函数。然后再调用一次Line 类自己的构造函数,最后用Display 函数计算a 、b 两点的长度。由于析构的时候顺序应该就是相反的,所以首先调用Line 类的析构函数,然后再调用五次Point 类的析构函数。得到如图所示结果。
二.任务二
1任务介绍及小组成员任务分配 任务介绍
某小型公司,主要有四类人员:经理、兼职技术人员、销售经理和兼职推销员。现在,需要存储这些人员的姓名、编号、级别、当月薪水,计算月薪总额并显示全部信息。人员编号基数为1000,每输入一个人员信息编号顺序加1。 月薪计算方法:
(1)经理拿固定月薪8000元;
(2)兼职技术人员按每小时100元领取月薪;
(3)兼职推销员的月薪按该推销员当月销售额的4%提成;
(4)销售经理既拿固定月薪也领取销售提成,固定月薪为5000元,销售提成为所管辖部门当月销售总额的5%。
程序要对所有人员有提升级别的功能。可将所有人员的初始级别均定为1级,然后进行升级,经理升为4级,兼职技术人员和销售经理升为3级,销售人员仍为1级。(本项提升级别的方法可以自行确定。) 设计要求:
在附件中给出的资料基础上进行完善。
完成类的设计
(1)按照给定资料,设计类 (2)进行类成员函数的实现 (3)给出代码的注释
(4)画出系统中出现的类的类图 屏幕显示采用菜单形式 整体功能
(1) 可以随时通过雇员的名字查询他的工资情况。
(2) 有查询结束标志。 (3) 有查询提示。 2设计思想及主要流程图 设计思想
该题要求对公司内四类人员:经理、兼职技术人员、销售经理和兼职推销员。分别存储他
们的姓名、编号、级别、当月薪水,计算月薪总额并显示全部信息。所以总体思路就是先
建立一个基类employee ,然后再建立四个派生类分别为class technician:public employee ,
class salesman:virtual public employee, class manager:virtual public employee 和class salesmanager:public employee
其分别为兼职技术人员、兼职推销员、经理和销售经理类,再根据各类员工的需要对各个类进行设计,然后再对基类和各个派生类中的各个成员函数进行定义,最后再对主函数进行设计。具体的是:题目的输出要求主要有员工的姓名,编号,级别和本月工资,所以在基类中必须要有四个数据成员
char *name(姓名)
int individualempNo(个人编号), int grade(级别) float accumpay(月薪总额)
为方便下面派生类的调用可将他们定为保护的,然后根据具体的计算等可再定义成员 static int employeeNo;//本公司职员编号目前最大值 employee(); //构造函数
~employee(); //析构函数 virtual void pay()=0; //计算月薪函数 virtual void promote(int increment=0); //升级函数
virtual void displaystatus()=0; //显示人员信息
由于各个经理、兼职技术人员、销售经理和兼职推销员的月工资计算都是不同的,其级别也是不同的,所以要分别对四个派生类定义不同的成员,如对兼职技术人员类可定义一下这写成员 private:
float hourlyrate; //每小时酬金 int workhours; //当月工作时间 public:
technician(); //构造函数 void promote(int);//升级函数 void pay(); //计算月薪函数
void displaystatus(); //显示人员函数
然后是对基类和四个派生类的各个构造函数,析构函数和成员函数进行定义。
基类的构造函数employee::employee()其作用主要为输入姓名,编号,对员工的初级级别和工资赋初值;
基类的析构函数employee::~employee()其作用是在析构函数中删除为存放姓名动态分配
的内存空间;
基类的成员函数void employee::promote(int increment)其作用是对员工的级别进行升级,提升的级数由increment 指定。
兼职技术人员类的构造函数technician::technician()其作用是对员工每小时酬金赋初值为100;
兼职技术人员类的成员函数void technician::promote(int)其作用是定义兼职技术人员的级别;
兼职技术人员类的成员函数void technician::pay()其作用是计算该类员工的月工资; 兼职技术人员类的成员函数void technician::displaystatus()其作用是显示人员信息。 兼职推销人员类构造函数salesman::salesman()其作用是对该类员工的销售提成比例赋初值为0.04;
兼职推销人员类成员函数void salesman::promote(int) 其作用是定义兼职推销人员的级别;
兼职推销人员类成员函数void salesman::pay()其作用是计算该类员工的月工资; 兼职推销人员类成员函数void salesman::displaystatus()其作用是显示人员信息。 经理类构造函数manager::manager()其作用是对经理的固定月薪赋初值为8000; 经理类成员函数void manager::promote(int) 其作用是定义经理的级别; 经理类成员函数void manager::pay()其作用是计算该类员工的月工资; 经理类成员函数void manager::displaystatus()其作用是显示人员信息。
推销经理类构造函数。salesmanager::salesmanager()其作用是对推销经理的固定月薪赋初值为5000,销售提成比例赋初值为0.05;
推销经理类成员函数void salesmanager::promote(int) 其作用是定义推销经理的级别; 推销经理类成员函数void salesmanager::pay()其作用是计算该类员工的月工资; 推销经理类成员函数void salesmanager::displaystatus()其作用是显示人员信息。 另外,为方面后面,可将基类中的
virtual void pay()=0; //计算月薪函数 virtual void promote(int increment=0); //升级函数 virtual void displaystatus()=0; //显示人员信息 这几个成员函数定义为虚函数。
最后是对主函数的具体设计:首先为了一定的美观及清晰,可再开始就输出
cout
cout
cout
********"
cout
3主要程序清单
#include 分比 #include float sales; //当月销售额 class employee public: { salesman(); //构造函数 protected: void promote(int); //升级函数 char *name; //姓名 void pay(); //计算月薪函数 int individualempNo; //个人编号 void displaystatus(); //显示人员函数 int grade; //级别 float accumpay; //月薪总额 static int employeeNo;//本公司职员编号目前最大值 public: employee(); //构造函数 ~employee(); //析构函数 virtual void pay()=0; //计算月薪函数 virtual void promote(int increment=0); //升级函数 virtual void displaystatus()=0; //显示人员信息 }; //兼职技术人员类 class technician:public employee { private: float hourlyrate; //每小时酬金 int workhours; //当月工作时间 public: technician(); //构造函数 void promote(int);//升级函数 void pay(); //计算月薪函数 void displaystatus(); //显示人员函数 }; //兼职推销员类 class salesman:virtual public employee { protected: float commrate;//按销售额提取酬金的百};
//经理类 class manager:virtual public employee
{ protected: float monthlypay;//固定月薪数 public:
manager(); //构造函数 void promote(int); //升级函数 void pay(); //计算月薪函数 void displaystatus();//显示人员函数 }; //销售经理类 class salesmanager:public manager,public salesman { public:
salesmanager();//构造函数 void promote(int);//升级函数 void pay(); //计算月薪函数 void displaystatus();//显示人员函数 }; int employee::employeeNo=1000;//员工编号基数为1000 employee::employee() {
char namestr[50];//输入雇员姓名时首先临时存放在namestr 中 cout>namestr;
name=new char[strlen(namestr)+1];//动态申请用于存放姓名的内存空间
strcpy(name,namestr);//将临时存放的姓名复制到name
individualempNo=employeeNo++;//新输入的员工,其编号为目前最大编号加1 grade=1; //级别初级为1
accumpay=0.0; //月薪总额初值为0 }
employee::~employee() {
delete name; //在析构函数中删除为存放姓名动态分配的内存空间 }
void employee::promote(int increment) {
grade+=increment;//升级,提升的级数由increment 指定 }
//兼职技术人员
technician::technician()
{
hourlyrate=100;//每小时酬金100 }
void technician::promote(int) {
employee::promote(2);//级别 }
void technician::pay()
{cout
cin>>workhours;
accumpay=hourlyrate*workhours;//计算月薪,按小时计算
coutvoid technician::displaystatus()//显示人员信息 {
cout//兼职推销人员
salesman::salesman() {
commrate=0.04; //销售提成比例4% }
void salesman::promote(int) {
employee::promote(0); }
void salesman::pay() {
cout
cin>>sales;
accumpay=sales*commrate;//月薪=销售提成
coutvoid salesman::displaystatus()//显示人员信息
{
cout//经理
manager::manager()
{
monthlypay=8000;//固定月薪8000 }
void manager::promote(int) {
employee::promote(3); }
void manager::pay() {
accumpay=monthlypay;//月薪总额即固定月薪数
coutvoid manager::displaystatus()//显示人员信息 {
cout//销售经理
salesmanager::salesmanager() {
monthlypay=5000; commrate=0.005; }
void salesmanager::promote(int) {
employee::promote(2); }
void salesmanager::pay() {
cout
辖部门本月的销售总额";
cin>>sales;
accumpay=monthlypay+commrate*sales;//月薪=固定工资+销售提成
coutvoid salesmanager::displaystatus()//显示人员信息 {
coutint main() {
cout
******************************************* "
cout
人 事 管 理 系 统 "
cout
******************************************* "
cout
cout
cout
技术人员 3. 销售经理 b->pay(); 4. 销售人员 *"
cout
cout> a; switch(a)
{case 0:break;
case 1:{ manager m1; employee* a; a=&m1;
a->promote(); a->pay();
a->displaystatus();}goto biaohao; break;
case 2:{technician t1; employee* b; b=&t1; b->promote();
b->displaystatus();}goto biaohao;break;
case 3:{salesmanager sm1; employee* c; c=&sm1;
c->promote(); c->pay();
c->displaystatus();}goto biaohao;break;
case 4:{salesman s1;
employee* d; d=&s1;
d->promote(); d->pay();
d->displaystatus();}goto biaohao;break;
default:cout
return 0;
}
4. 运行结果及分析
分析
当桌面出现请选择功能后,用户就该输入0到4的数字,选择其它数字时,程序就会自动出现“你输入有误,请重试”的字样,若选择1,则程序进入case 1,在case 1中会定义一个manager 类的对象m1和指向基类对象m1的指针变量a ,通过指针来指向虚函数
promote(),pay()和displaystatus(),从而输出
若选择2,则程序进入case 2,在case 2中会定义一个technician 类的对象t1和指向基类对象t1的指针变量b ,通过指针来指向虚函数promote(),pay()和displaystatus(),从而输出
若选择3,则程序进入case 3,在case 3中会定义一个salesmanager 类的对象sm1和指向基类对象sm1的指针变量c ,通过指针来指向虚函数promote(),pay()和displaystatus(),从而输出
若选择4,则程序进入case 4,在case4中会定义一个salesman 类的对象s1和指向基类对象s1的指针变量d ,通过指针来指向虚函数promote(),pay()和displaystatus(),从而输出
三、收获、体会及建议
通过这个课程设计,我们学到了不少甚至在实际操作过程中犯的一些错误还会有意外的收获,感觉实训很有意思。在具体操作中对这学期所学的C++语言的理论知识得到巩固,达到实训的基本目的,也发现自己的不足之处,在以后的上机中应更加注意,同时体会到C++语言具有的语句简洁,使用灵活,执行效率高等特点。发现上机实训的重要作用,特别是对构造函数和析构函数的理解。
通过实际操作,学会 C++语言程序编程的基本步骤、基本方法,开发了自己的逻辑思维能力,培养了分析问题、解决问题的能力。深刻体会到“没有做不到的,只有想不到的”,“团结就是力量”,“实践是检验真理的标准”等寓意。