oop-实验4

task1

GradeCalc.hpp

 1 #pragma once
 2 
 3 #include<vector>
 4 #include<array>
 5 #include<string>
 6 
 7 class GradeCalc{
 8 public:
 9     GradeCalc(const std::string &cname);
10     void input(int n); // 录入n个成绩
11     void output() const; // 输出成绩
12     void sort(bool ascending = false); // 排序 (默认降序)
13     int min() const; // 返回最低分(如成绩未录入,返回-1)
14     int max() const; // 返回最高分 (如成绩未录入,返回-1)
15     double average() const; // 返回平均分 (如成绩未录入,返回0.0)
16     void info(); // 输出课程成绩信息
17 
18 private:
19     void compute();  //成绩统计
20 
21 private:
22     std::string course_name; // 课程名
23     std::vector<int> grades; // 课程成绩
24     std::array<int, 5> counts; // 保存各分数段人数([0, 60), [60, 70), [70, 80), [80,90), [90, 100]
25     std::array<double, 5> rates; // 保存各分数段人数占比
26     bool is_dirty; // 脏标记,记录是否成绩信息有变更
27 };

GradeCalc.cpp

 1 #include<algorithm>
 2 #include<array>
 3 #include<cstdlib>
 4 #include<iomanip>
 5 #include<iostream>
 6 #include<numeric>
 7 #include<string>
 8 #include<vector>
 9 
10 #include"GradeCalc.hpp"
11 
12 GradeCalc::GradeCalc(const std::string &cname):course_name(cname),is_dirty{true}{
13     counts.fill(0);
14     rates.fill(0);
15 }
16 
17 void GradeCalc::input(int n){
18     if(n<0){
19         std::cerr<<"无效输入!人数不能为负数";
20         std::exit(1);
21     }
22     grades.reserve(n);
23     int grade;
24     for(int i=0;i<n;){
25         std::cin>>grade;
26         if(grade<0||grade>100){
27             std::cerr<<"无效输入!分数须在[0,100]\n";
28             continue;
29         }
30         grades.push_back(grade);
31         ++i;
32     }
33     is_dirty=true; //设置脏标记,成绩信息有变更
34 }
35 
36 void GradeCalc::output() const{
37     for(auto grade:grades) std::cout<<grade<<" ";
38     std::cout<<std::endl;
39 }
40 
41 void GradeCalc::sort(bool ascending){
42     if(ascending) std::sort(grades.begin(),grades.end());
43     else std::sort(grades.begin(),grades.end(),std::greater<int>());
44 } 
45 
46 int GradeCalc::min() const{
47     if(grades.empty()) return -1;
48     auto it=std::min_element(grades.begin(),grades.end());
49     return *it; 
50 } 
51 
52 int GradeCalc::max() const{
53     if(grades.empty()) return -1;
54     auto it=std::max_element(grades.begin(),grades.end());
55     return *it;
56 }
57 
58 double GradeCalc::average() const{
59     if(grades.empty()) return 0.0;
60     double avg=std::accumulate(grades.begin(),grades.end(),0.0)/grades.size();
61     return avg;
62 }
63 
64 void GradeCalc::info(){
65     if(is_dirty) compute();
66     std::cout<<"课程名称:\t"<<course_name<<std::endl;
67     std::cout<<"平均分:\t"<<std::fixed<<std::setprecision(2)<<average()<<std::endl;
68     std::cout<<"最高分:\t"<<max()<<std::endl;
69     std::cout<<"最低分:\t"<<min()<<std::endl;
70     const std::array<std::string,5> grade_range{"[0, 60) ","[60, 70)","[70, 80)","[80, 90)","[90, 100]"};
71     for(int i=grade_range.size()-1;i>=0;i--){
72         std::cout<<grade_range[i]<<"\t:"<<counts[i]<<"人\t"<<std::fixed<<std::setprecision(2)<<rates[i]*100<<"%\n";
73     }
74 }
75 
76 void GradeCalc::compute(){  
77     if(grades.empty()) return;
78     counts.fill(0);
79     rates.fill(0.0);
80     //统计各分数段人数
81     for(auto grade:grades){
82         if(grade<60){
83             ++counts[0];
84         }else if(grade<70){
85             ++counts[1];
86         }else if(grade<80){
87             ++counts[2];
88         }else if(grade<90){
89             ++counts[3];
90         }else{
91             ++counts[4];
92         }
93     }
94     for(int i=0;i<rates.size();++i)
95         rates[i]=counts[i]*1.0/grades.size();
96     is_dirty=false;  //更新脏标记
97 }

demo1.cpp

 1 #include<iostream>
 2 #include<string>
 3 
 4 #include"GradeCalc.hpp"
 5 
 6 void test(){
 7     GradeCalc c1("OOP");
 8     std::cout<<"录入成绩:\n";
 9     c1.input(5);
10 
11     std::cout<<"输出成绩:\n";
12     c1.output();
13     
14     std::cout<<"排序后成绩:\n";
15     c1.sort();
16     c1.output();
17     
18     std::cout<<"*************成绩统计信息*************\n";
19     c1.info();
20 }
21 int main(){
22     test();
23 }

运行结果

image

 回答问题:

image

 

 

task2

GradeCalc.hpp

 1 #pragma once
 2 #include<array>
 3 #include<string>
 4 #include<vector>
 5 
 6 class GradeCalc:private std::vector<int>{
 7 public:
 8     GradeCalc(const std::string &cname);
 9     void input(int n); // 录入n个成绩
10     void output() const; // 输出成绩
11     void sort(bool ascending = false); // 排序 (默认降序)
12     int min() const; // 返回最低分(如成绩未录入,返回-1)
13     int max() const; // 返回最高分 (如成绩未录入,返回-1)
14     double average() const; // 返回平均分 (如成绩未录入,返回0.0)
15     void info(); // 输出课程成绩信息
16 
17 private:
18     void compute();  //成绩统计
19 
20 private:
21     std::string course_name; // 课程名
22     std::vector<int> grades; // 课程成绩
23     std::array<int, 5> counts; // 保存各分数段人数([0, 60), [60, 70), [70, 80), [80,90), [90, 100]
24     std::array<double, 5> rates; // 保存各分数段人数占比
25     bool is_dirty; // 脏标记,记录是否成绩信息有变更
26 };

GradeCalc.cpp

  1 #include <algorithm>
  2 #include <array>
  3 #include <cstdlib>
  4 #include <iomanip>
  5 #include <iostream>
  6 #include <numeric>
  7 #include <string>
  8 #include <vector>
  9 #include "GradeCalc.hpp"
 10 
 11 GradeCalc::GradeCalc(const std::string &cname): course_name{cname}, is_dirty{true}{
 12     counts.fill(0);
 13     rates.fill(0);
 14 }
 15 
 16 void GradeCalc::input(int n){
 17     if(n<0){
 18         std::cerr<<"无效输入! 人数不能为负数\n";
 19         return;
 20     }
 21     this->reserve(n);
 22     int grade;
 23     for(int i=0;i<n;){
 24         std::cin >> grade;
 25         if(grade < 0 || grade > 100) {
 26             std::cerr << "无效输入! 分数须在[0,100]\n";
 27             continue;
 28         }
 29         this->push_back(grade);
 30         ++i;
 31     }
 32     is_dirty=true;
 33 }
 34 
 35 void GradeCalc::output() const{
 36     for(auto g:*this)
 37         std::cout<<g<<' ';
 38     std::cout<<std::endl;
 39 }
 40 
 41 void GradeCalc::sort(bool ascending){
 42     if(ascending) std::sort(this->begin(),this->end());
 43     else std::sort(this->begin(),this->end(),std::greater<int>());
 44 }
 45 
 46 int GradeCalc::min() const{
 47     if(this->empty())
 48         return -1;
 49     return *std::min_element(this->begin(), this->end());
 50 }
 51 
 52 int GradeCalc::max() const{
 53     if(this->empty())
 54         return -1;
 55     return *std::max_element(this->begin(), this->end());
 56 }
 57 
 58 double GradeCalc::average() const {
 59     if(this->empty())
 60         return 0.0;
 61     double avg = std::accumulate(this->begin(), this->end(), 0.0) / this->size();
 62     return avg;
 63 }
 64 void GradeCalc::info() {
 65     if(is_dirty) compute();
 66     std::cout << "课程名称:\t" << course_name << std::endl;
 67     std::cout << "平均分:\t" << std::fixed << std::setprecision(2) << average() <<
 68     std::endl;
 69     std::cout << "最高分:\t" << max() << std::endl;
 70     std::cout << "最低分:\t" << min() << std::endl;
 71     const std::array<std::string, 5> grade_range{"[0, 60) ",
 72     "[60, 70)",
 73     "[70, 80)",
 74     "[80, 90)",
 75     "[90, 100]"};
 76     for(int i = grade_range.size()-1; i >= 0; --i)
 77         std::cout << grade_range[i] << "\t: " << counts[i] << "人\t"<< std::fixed << std::setprecision(2) << rates[i]*100 << "%\n";
 78 }
 79 
 80 void GradeCalc::compute() {
 81     if(this->empty())
 82         return;
 83     counts.fill(0);
 84     rates.fill(0);
 85     // 统计各分数段人数
 86     for(int grade: *this) {
 87         if(grade < 60)
 88             ++counts[0]; // [0, 60)
 89         else if (grade < 70)
 90             ++counts[1]; // [60, 70)
 91         else if (grade < 80)
 92             ++counts[2]; // [70, 80)
 93         else if (grade < 90)
 94             ++counts[3]; // [80, 90)
 95         else
 96             ++counts[4]; // [90, 100]
 97     }
 98     // 统计各分数段比例
 99     for(int i = 0; i < rates.size(); ++i)
100         rates[i] = counts[i] * 1.0 / this->size();
101     is_dirty = false;
102 }

demo2.cpp

 1 #include <iostream>
 2 #include <string>
 3 #include "GradeCalc.hpp"
 4 void test() {
 5     GradeCalc c1("OOP");
 6 
 7     std::cout << "录入成绩:\n";
 8     c1.input(5);
 9     
10     std::cout << "输出成绩:\n";
11     c1.output();
12     
13     std::cout << "排序后成绩:\n";
14     c1.sort(); c1.output();
15     
16     std::cout << "*************成绩统计信息*************\n";
17     c1.info();
18 }
19 int main() {
20     test();
21 }

 运行结果

image

 回答问题:

image

 

 

task3

Graph.hpp

 1 #pragma once
 2 
 3 #include<string>
 4 #include<vector>
 5 
 6 enum class GraphType{circle,triangle,rectangle};
 7 
 8 //Grape类定义
 9 class Graph{
10 public:
11     virtual void draw(){};
12     virtual ~Graph()=default;
13 };
14 
15 //Circle类
16 class Circle:public Graph{
17 public:
18     void draw();
19 };
20 
21 //Triangle类
22 class Triangle:public Graph{
23 public: 
24     void draw();
25 };
26 
27 //Rectangle类
28 class Rectangle:public Graph{
29 public:
30     void draw();
31 };
32 
33 //Canvas (画布)
34 class Canvas{
35 public:
36     void add(const std::string &type);
37     void paint() const;
38     ~Canvas();
39 private:
40     std::vector<Graph*> graphs;
41 };
42 
43 //工具函数
44 GraphType str_to_GraphType(const std::string &s); //string->enum
45 Graph* make_graph(const std::string &type); //创建图形,返回堆对象指针

Graph.cpp

 1 #include<algorithm>
 2 #include<cctype>
 3 #include<iostream>
 4 #include<string>
 5 
 6 #include"Graph.hpp"
 7 
 8 void Circle::draw(){ std::cout<<"draw a circle...\n"; }
 9 
10 void Triangle::draw(){ std::cout<<"draw a triangle...\n"; }
11 
12 void Rectangle::draw(){ std::cout<<"draw a rectangle...\n"; }
13 
14 void Canvas::add(const std::string &type){
15     Graph* g=make_graph(type);
16     if(g)
17         graphs.push_back(g);
18 }
19 
20 void Canvas::paint() const{
21     for(Graph *g:graphs)
22         g->draw();
23 }
24 
25 Canvas::~Canvas(){
26     for(Graph* g:graphs)
27         delete g;
28 }
29 
30 //工具函数实现,字符串->枚举转换
31 GraphType str_to_GraphType(const std::string &s){
32     std::string t=s;
33     std::transform(s.begin(),s.end(),t.begin(),[](unsigned char c){ return std::tolower(c); });
34     if(t=="circle") return GraphType::circle;
35     if(t=="triangle") return GraphType::triangle;
36     if(t=="rectangle") return GraphType::rectangle;
37     return GraphType::circle;  //缺省返回
38 }
39 
40 //创建图形,返回堆对象指针
41 Graph* make_graph(const std::string& type){
42     switch(str_to_GraphType(type)){
43         case GraphType::circle: return new Circle;
44         case GraphType::triangle: return new Triangle;
45         case GraphType::rectangle: return new Rectangle;
46         default: return nullptr;
47     }
48 }

 demo3.cpp

 1 #include <string>
 2 #include "Graph.hpp"
 3 void test() {
 4     Canvas canvas;
 5     canvas.add("circle");
 6     canvas.add("triangle");
 7     canvas.add("rectangle");
 8     canvas.paint();
 9 }
10 int main() {
11     test();
12 }

运行结果

image

 回答问题:

image

 

 

task4

问题场景描述:
模拟设计了一个玩具工厂,ToyFactory 类可以:向工厂添加任意数量、任意类型的玩具(add());查看工厂支持的所有玩具类别及其功能特点(info());指挥工厂内所有已生产的玩具同时进行技能表演(play)。
main函数:在main函数中输入玩具的类型,生产出了四种不同功能的毛绒玩具:会跳舞的小熊、可遥控行驶的小车、会播放多首歌曲的音乐盒、以及会前后弹跳的玩具青蛙。每种玩具都具备独特的play_skill,且对外提供统一的玩具接口(play_skill)。

各类之间的关系(继承、组合等)及设计理由:
Toy是所有玩具类的基类,Bear,Remote_car,Music_box,Frog都继承了Toy类,是is-a关系,且四个子类都重写了Toy当中的虚函数play_skill(),在这个函数中调用了他们各自的skill,play_skill作为对外的公共接口用于在ToyFactory类中调用以展示技能,ToyFactory类中用到了组合类,体现的是has-a的关系,std::vector<Toy*> toys;,组合一个vector类用于存储玩具对象,std::vector<std::pair<std::string, std::string>>还有一个用于存储玩具工厂所包含的玩具类型以及对应的功能。

Toy.hpp

 1 #pragma once
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<string>
 5 
 6 enum class Toys_name{Bear,Remote_car,Music_box,Frog,Unknown};
 7 
 8 class Toy{
 9 public:
10     Toy(const std::string& name,const std::string &type,const std::string skill);
11     virtual void play_skill(){}
12     virtual ~Toy()=default;
13     std::string get_name(){ return toy_name; }
14     std::string get_type(){ return toy_type; }
15     std::string get_skill(){ return toy_skill; }
16 protected:
17     std::string toy_name;
18     std::string toy_type;
19     std::string toy_skill;
20 };
21 
22 //会跳舞的小熊
23 class Bear:public Toy{
24 public:
25     Bear(const std::string& name);
26     void dance_a();
27     void dance_b();
28     void play_skill();
29 };
30 
31 //遥控毛绒小车
32 class Remote_car:public Toy{
33 public:
34     Remote_car(const std::string& name,int r);
35     void move(bool dir);
36     void play_skill();
37 private:
38     int rate; //车速
39     bool stop=true; //判断小车此时是否为静止状态
40 };
41 
42 //毛绒音乐盒
43 class Music_box:public Toy{
44 public:
45     Music_box(const std::string& name,int num);
46     void play_skill();
47 private:
48     int song_num; //歌曲数量
49 };
50 
51 //可弹跳的青蛙
52 class Frog:public Toy{
53 public:
54     Frog(const std::string& name);
55     void jump(bool dir);    
56     void play_skill();
57 private:
58     bool stop=true;
59 };
60 
61 //将string->enum
62 Toys_name str_to_enum(const std::string& s);
63 
64 Toy* make_toys(const std::string &s);

Toy.cpp

 1 #include<iostream>
 2 #include<string>
 3 #include<algorithm>
 4 
 5 #include"Toy.hpp"
 6 
 7 Toy::Toy(const std::string& name,const std::string &type,const std::string skill):toy_name(name),toy_type(type),toy_skill(skill){}
 8 Bear::Bear(const std::string& name):Toy(name,"动物类玩具","跳舞"){}
 9 void Bear::dance_a(){ std::cout<<"小熊开始跳舞蹈A...\n"; }
10 void Bear::dance_b(){ std::cout<<"小熊开始跳舞蹈B...\n"; }
11 void Bear::play_skill(){
12     dance_a();
13     dance_b();
14 }
15 
16 Remote_car::Remote_car(const std::string& name,int r):Toy(name,"遥控类玩具","行驶"),rate{r}{}
17 void Remote_car::move(bool dir){ //dir为true时前进,反之后退
18     if(stop) return;
19     if(dir) std::cout<<"小车正在以"<<rate<<"m/s"<<"的速度向前移动\n";
20     else std::cout<<"小车正在以"<<rate<<"m/s"<<"的速度向后移动\n";
21 }
22 void Remote_car::play_skill(){
23     stop=false;
24     move(true);
25     move(false);
26     stop=false;
27     std::cout<<"小车停止移动...\n";
28 }
29 
30 Music_box::Music_box(const std::string& name,int num):Toy(name,"发声类玩具","放音乐"),song_num{num}{}
31 void Music_box::play_skill(){
32     std::cout<<"音乐盒共有"<<song_num<<"首歌,开始播放歌曲...\n";
33     for(int i=1;i<=song_num;i++){
34         std::cout<<"正在播放歌曲"<<i<<"\n";
35     }
36 }
37 
38 Frog::Frog(const std::string& name):Toy(name,"动作类玩具类","弹跳"){}
39 void Frog::jump(bool dir){ //dir为true向前跳,反之向后跳
40     if(stop) return;
41     if(dir) std::cout<<"小青蛙向前跳\n";
42     else std::cout<<"小青蛙向后跳\n";
43 }
44 void Frog::play_skill(){
45     stop=false;
46     jump(true);
47     jump(false);
48     stop=false;
49     std::cout<<"小青蛙停止跳跃...";
50 }
51 
52 //将string->enum
53 Toys_name str_to_enum(const std::string& s){   
54     std::string t=s;
55     std::transform(s.begin(),s.end(),t.begin(),[](unsigned char c){ return std::tolower(c); });
56     if(t=="bear") return Toys_name::Bear;
57     if(t=="music_box") return Toys_name::Music_box;
58     if(t=="frog") return Toys_name::Frog;
59     if(t=="remote_car") return Toys_name::Remote_car;
60     return Toys_name::Unknown; //缺省返回
61 }
62 
63 Toy* make_toys(const std::string& s){
64     switch(str_to_enum(s)){
65         case Toys_name::Bear: return new Bear("小熊"); 
66         case Toys_name::Remote_car: return new Remote_car("遥控小车", 5); 
67         case Toys_name::Music_box: return new Music_box("音乐盒", 3); 
68         case Toys_name::Frog: return new Frog("小青蛙"); 
69         case Toys_name::Unknown:
70         default:
71             std::cout << "错误:无法根据枚举值创建玩具。" << std::endl;
72             return nullptr;
73     }
74 }

ToyFactory.hpp

 1 #pragma once
 2 #include<string>
 3 #include<vector>
 4 #include<utility>
 5 
 6 #include"Toy.hpp"
 7 
 8 class ToyFactory{
 9 public:
10     void info() const;
11     void play() const;
12     void add(const std::string &type);
13     ~ToyFactory();
14 
15 private:
16     std::vector<Toy*> toys;
17     std::vector<std::pair<std::string, std::string>> toy_categories={
18         {"动物类玩具", "模拟动物形态/行为"},
19         {"发声类玩具", "能播放音乐/模拟声音"},
20         {"动作类玩具", "能完成特定动作"},
21         {"遥控类玩具", "远程操控移动/动作"}
22     }; //玩具工厂所包含的玩具类型以及对应的功能
23 };

ToyFactory.cpp

 1 #include<vector>
 2 
 3 #include"ToyFactory.hpp"
 4 #include"Toy.hpp"
 5 
 6 void ToyFactory::add(const std::string &type){
 7     Toy *t=make_toys(type);
 8     if(t) toys.push_back(t);
 9 }
10 
11 void ToyFactory::play() const{
12     for(Toy *t:toys){
13         std::cout<<"玩具名称:"<<t->get_name()<<" 玩具类型:"<<t->get_type()<<" 玩具技能:"<<t->get_skill();
14         std::cout<<"\nshow skill: \n";
15         t->play_skill();
16         std::cout<<"\n";
17     }
18 }
19 
20 void ToyFactory::info() const{
21     std::cout<<"玩具工厂生产的四种玩具极其特点:"<<"\n";
22     for(int i=0;i<toy_categories.size();i++){
23         std::cout<<i+1<<" "<<toy_categories[i].first<<":"<<toy_categories[i].second<<std::endl;
24     }
25     std::cout<<"\n";
26     std::cout<<"展示玩具技能:"<<"\n";
27     play();
28 }
29 
30 ToyFactory::~ToyFactory(){
31     for(auto t:toys) delete t;
32 }

demo4.cpp

 1 #include<iostream>
 2 #include"Toy.hpp"
 3 #include"ToyFactory.hpp"
 4 
 5 int main(){
 6     ToyFactory t;
 7     t.add("Bear");
 8     t.add("Music_box");
 9     t.add("Remote_car"); 
10     t.add("Frog");
11     t.info();
12 }

运行结果

image

 

posted @ 2025-11-27 00:40  fg-ever  阅读(3)  评论(0)    收藏  举报