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 }
运行结果

回答问题:

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 }
运行结果

回答问题:

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 }
运行结果

回答问题:

task4
问题场景描述:
模拟设计了一个玩具工厂,ToyFactory 类可以:向工厂添加任意数量、任意类型的玩具(add());查看工厂支持的所有玩具类别及其功能特点(info());指挥工厂内所有已生产的玩具同时进行技能表演(play)。
main函数:在main函数中输入玩具的类型,生产出了四种不同功能的毛绒玩具:会跳舞的小熊、可遥控行驶的小车、会播放多首歌曲的音乐盒、以及会前后弹跳的玩具青蛙。每种玩具都具备独特的play_skill,且对外提供统一的玩具接口(play_skill)。
各类之间的关系(继承、组合等)及设计理由:
Toy是所有玩具类的基类,Bear,Remote_car,Music_box,Frog都继承了Toy类,是is-a关系,且四个子类都重写了Toy当中的虚函数play_skill()(其实这里的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 }
运行结果
