实验04
任务一
GradeCalc.hpp
#pragma once #include<array> #include<string> #include<vector> class GradeCalc { public: GradeCalc(const std::string &cname); void input (int n); void output() const; void sort(bool ascending=false); int min() const; int max() const; double average() const; void info(); private: void compute(); private: std::string course_name; std::vector<int>grades; std::array<int, 5> counts; std::array<double, 5> rates; bool is_dirty; };
GradeCalc.cpp
#include<algorithm> #include<array> #include<cstdlib> #include<iomanip> #include<iostream> #include<numeric> #include<string> #include<vector> #include"GradeCalc.hpp" GradeCalc::GradeCalc(const std::string &cname):course_name{cname},is_dirty{true} { counts.fill(0); rates.fill(0); } void GradeCalc::input(int n) { if(n<0) { std::cerr<<"无效输入!人数不能为负数\n"; std::exit(1); } grades.reserve(n); int grade; for(int i=0;i<n;) { std::cin>>grade; if(grade<0||grade>100) { std::cerr<<"无效输入!分数须在[0,100]\n"; continue; } grades.push_back(grade); ++i; } is_dirty=true; } void GradeCalc::output() const { for(auto grade:grades) std::cout<<grade<<' '; std::cout<<std::endl; } void GradeCalc::sort(bool ascending) { if(ascending) std::sort(grades.begin(),grades.end()); else std::sort(grades.begin(),grades.end(),std::greater<int>()); } int GradeCalc::min() const { if(grades.empty()) return -1; auto it=std::min_element(grades.begin(),grades.end()); return*it; } int GradeCalc::max() const { if(grades.empty()) return -1; auto it=std::max_element(grades.begin(),grades.end()); return *it; } double GradeCalc::average() const { if(grades.empty()) return 0.0; double avg=std::accumulate(grades.begin(),grades.end(),0.0)/grades.size(); return avg; } void::GradeCalc::info() { if(is_dirty) compute(); std::cout<<"课程名称:\t"<<course_name<<std::endl; std::cout<<"平均分:\t"<<std::fixed<<std::setprecision(2)<<average()<<std::endl; std::cout<<"最高分:\t" << max() << std::endl; std::cout<<"最低分:\t" << min() << std::endl; const std::array<std::string, 5>grade_range{"[0 , 60)","[60, 70)","[70, 80)","[80, 90)","[90, 100]"}; for(int i=grade_range.size()-1;i>=0;--i) std::cout<<grade_range[i]<<"\t :"<<counts[i]<<"人\t"<<std::fixed<<std::setprecision(2)<<rates[i]*100<<"%\n"; } void GradeCalc::compute() { if(grades.empty()) return; counts.fill(0); rates.fill(0.0); for(auto grade:grades) { if(grade<60) ++counts[0]; else if(grade<70) ++counts[1]; else if(grade<80) ++counts[2]; else if(grade<90) ++counts[3]; else ++counts[4]; } for(int i=0;i<rates.size();++i) rates[i]=counts[i]*1.0/grades.size(); is_dirty=false; }
#include<algorithm> #include<array> #include<cstdlib> #include<iomanip> #include<iostream> #include<numeric> #include<string> #include<vector> #include"GradeCalc.hpp" GradeCalc::GradeCalc(const std::string &cname):course_name{cname},is_dirty{true} { counts.fill(0); rates.fill(0); } void GradeCalc::input(int n) { if(n<0) { std::cerr<<"无效输入!人数不能为负数\n"; std::exit(1); } grades.reserve(n); int grade; for(int i=0;i<n;) { std::cin>>grade; if(grade<0||grade>100) { std::cerr<<"无效输入!分数须在[0,100]\n"; continue; } grades.push_back(grade); ++i; } is_dirty=true; } void GradeCalc::output() const { for(auto grade:grades) std::cout<<grade<<' '; std::cout<<std::endl; } void GradeCalc::sort(bool ascending) { if(ascending) std::sort(grades.begin(),grades.end()); else std::sort(grades.begin(),grades.end(),std::greater<int>()); } int GradeCalc::min() const { if(grades.empty()) return -1; auto it=std::min_element(grades.begin(),grades.end()); return*it; } int GradeCalc::max() const { if(grades.empty()) return -1; auto it=std::max_element(grades.begin(),grades.end()); return *it; } double GradeCalc::average() const { if(grades.empty()) return 0.0; double avg=std::accumulate(grades.begin(),grades.end(),0.0)/grades.size(); return avg; } void::GradeCalc::info() { if(is_dirty) compute(); std::cout<<"课程名称:\t"<<course_name<<std::endl; std::cout<<"平均分:\t"<<std::fixed<<std::setprecision(2)<<average()<<std::endl; std::cout<<"最高分:\t" << max() << std::endl; std::cout<<"最低分:\t" << min() << std::endl; const std::array<std::string, 5>grade_range{"[0 , 60)","[60, 70)","[70, 80)","[80, 90)","[90, 100]"}; for(int i=grade_range.size()-1;i>=0;--i) std::cout<<grade_range[i]<<"\t :"<<counts[i]<<"人\t"<<std::fixed<<std::setprecision(2)<<rates[i]*100<<"%\n"; } void GradeCalc::compute() { if(grades.empty()) return; counts.fill(0); rates.fill(0.0); for(auto grade:grades) { if(grade<60) ++counts[0]; else if(grade<70) ++counts[1]; else if(grade<80) ++counts[2]; else if(grade<90) ++counts[3]; else ++counts[4]; } for(int i=0;i<rates.size();++i) rates[i]=counts[i]*1.0/grades.size(); is_dirty=false; }
demo1.cpp
#include <iostream> #include <string> #include "GradeCalc.hpp" void test() { GradeCalc c1("OOP"); std::cout << "录入成绩:\n"; c1.input(5); std::cout << "输出成绩:\n"; c1.output(); std::cout << "排序后成绩:\n"; c1.sort(); c1.output(); std::cout << "*************成绩统计信息*************\n"; c1.info(); } int main() { test(); }
运行结果截图:

问题1:组合关系识别
std::vector<int> grades,功能是存储成绩
std::array<int, 5> counts,功能是统计人数
std::array<double, 5> rates,存各分段百分率
int n=grades.size();
if(n%2)
min=grades[n/2];
else
min=(grades[n/2]+grades[n/2-1])/2.0
不能去掉。如果去掉,当第二次录入成绩,再次调用 compute ,counts 会累积上一次统计的数据,出现统计错误。
有影响。reserve(n) 预分配空间,可减少扩容次数,提高效率。
实验任务2:
GradeCalc2.hpp
#pragma once #include<array> #include<string> #include<vector> class GradeCalc:private std::vector<int> { public: GradeCalc(const std::string &cname); void input(int n); void output() const; void sort(bool ascending=false); int min() const; int max() const; double average() const; void info(); private: void compute(); private: std::string course_name; std::array<int, 5> counts; std::array<double, 5> rates; bool is_dirty; };
GradeCalc2.cpp
#include <algorithm> #include <array> #include <cstdlib> #include <iomanip> #include <iostream> #include <numeric> #include <string> #include <vector> #include "GradeCalc2.hpp" GradeCalc ::GradeCalc(const std::string &cname):course_name{cname},is_dirty{true} { counts.fill(0); rates.fill(0); } void GradeCalc::input(int n) { if(n<0) { std::cerr<<"无效输入! 人数不能为负数\n"; return; } this->reserve(n); int grade; for(int i=0;i<n;) { std::cin>>grade; if(grade<0||grade>100) { std::cerr<< "无效输入! 分数须在[0,100]\n"; continue; } this->push_back(grade); ++i; } is_dirty=true; } void GradeCalc::output() const { for(auto grade:*this) std::cout<<grade<<' '; std::cout<<std::endl; } void GradeCalc::sort(bool ascending) { if(ascending) std::sort(this->begin(),this->end()); else std::sort(this->begin(),this->end(),std::greater<int>()); } int GradeCalc::min() const { if(this->empty()) return -1; return *std::min_element(this->begin(),this->end()); } int GradeCalc::max() const { if(this->empty()) return -1; return *std::max_element(this->begin(),this->end()); } double GradeCalc::average() const { if(this->empty()) return 0.0; double avg = std::accumulate(this->begin(), this->end(), 0.0) / this->size(); return avg; } void GradeCalc::info() { if(is_dirty) compute(); std::cout << "课程名称:\t" << course_name << std::endl; std::cout << "平均分:\t" << std::fixed << std::setprecision(2) << average() << std::endl; std::cout << "最高分:\t" << max() << std::endl; std::cout << "最低分:\t" << min() << std::endl; const std::array<std::string, 5> grade_range{"[0 , 60)","[60, 70)","[70, 80)","[80, 90)","[90,100]"}; for(int i = grade_range.size()-1; i >= 0; --i) std::cout << grade_range[i] << "\t: " << counts[i] << "人\t"<< std::fixed << std::setprecision(2) <<rates[i]*100 << "%\n"; } void GradeCalc::compute() { if(this->empty()) return; counts.fill(0); rates.fill(0); for(int grade: *this) { if(grade < 60) ++counts[0]; else if (grade < 70) ++counts[1]; else if (grade < 80) ++counts[2]; else if (grade < 90) ++counts[3]; else ++counts[4]; } for(int i=0;i<rates.size();++i) rates[i]=counts[i]*1.0/this->size(); is_dirty=false; }
demo2.cpp
#include <iostream> #include <string> #include "GradeCalc.hpp" void test() { GradeCalc c1("OOP"); std::cout << "录入成绩:\n"; c1.input(5); std::cout << "输出成绩:\n"; c1.output(); std::cout << "排序后成绩:\n"; c1.sort(); c1.output(); std::cout << "*************成绩统计信息*************\n"; c1.info(); } int main() { test(); }
实验运行结果截图:

class GradeCalc : private std::vector<int>
#pragma once #include<string> #include<vector> enum class GraphType{circle,triangle,rectangle}; class Graph { public: virtual void draw(){} virtual ~Graph()=default; }; class Circle:public Graph { public: void draw(); }; class Triangle : public Graph { public: void draw(); }; class Rectangle:public Graph { public: void draw(); }; class Canvas { public: void add(const std::string& type); void paint() const; ~Canvas(); private: std::vector<Graph*>graphs; }; GraphType str_to_GraphType(const std::string& s); Graph* make_graph(const std::string& type);
Graph.cpp
#include <algorithm> #include <cctype> #include <iostream> #include <string> #include "Graph.hpp" void Circle::draw() { std::cout<<"draw a circle...\n"; } void Triangle::draw() { std::cout<<"draw a triangle...\n"; } void Rectangle::draw() { std::cout<<"draw a rectangle...\n"; } void Canvas::add(const std::string& type) { Graph* g=make_graph(type); if(g) graphs.push_back(g); } void Canvas::paint() const { for(Graph* g:graphs) g->draw(); } Canvas::~Canvas() { for(Graph* g:graphs) delete g; } GraphType str_to_GraphType(const std::string& s) { std::string t=s; std::transform(s.begin(),s.end(),t.begin(),[](unsigned char c){return std::tolower(c);}); if(t=="circle") return GraphType::circle; if (t == "triangle") return GraphType::triangle; if (t == "rectangle") return GraphType::rectangle; return GraphType::circle; } Graph* make_graph(const std::string& type) { switch(str_to_GraphType(type)) { case GraphType::circle: return new Circle; case GraphType::triangle: return new Triangle; case GraphType::rectangle: return new Rectangle; default:return nullptr; } }
demo3.cpp
#include <string> #include "Graph.hpp" void test() { Canvas canvas; canvas.add("circle"); canvas.add("triangle"); canvas.add("rectangle"); canvas.paint(); } int main() { test(); }
实验运行结果截图:

class Star : public Graph {
public:
void draw() override;
};
并在枚举中加入
enum class GraphType { circle, triangle, rectangle, star };
Graph.cpp中添加Star::draw()实现;make_graph中添加分支case GraphType::star: return new Star; 在str_to_GraphType函数中新增Star字符串转换为枚举类型功能
然后让工厂统一调用这些玩具的“功能接口”,就是不管是什么玩具,都能通过同一个函数来触发它们的技能。
对象关系:
Toy(基类)
-
所有玩具都有名字、类型
-
有一个虚函数
special(),每种玩具重写它
Bear / Cat / Robot(派生类)
分别重写自己的技能,比如拥抱、卖萌等
ToyFactory(组合)
-
工厂里面放一堆
Toy*(这里用了组合) -
工厂有
add来添加玩具 -
有
show_all()来展示所有玩具的技能
#pragma once #include <string> #include <vector> #include <iostream> class Toy { public: Toy(const std::string& name, const std::string& type) : name(name), type(type) {}
virtual void special() { std::cout << name << " has no special ability.\n"; } virtual void info() { std::cout << "玩具名称: " << name << " 类型: " << type << "\n"; } virtual ~Toy() = default; protected: std::string name; std::string type; }; // 熊 class Bear : public Toy { public: Bear(const std::string& name) : Toy(name, "熊") {} void special() override { std::cout << name << "请给我一个拥抱!\n"; } }; // 猫 class Cat : public Toy { public: Cat(const std::string& name) : Toy(name, "猫") {} void special() override { std::cout << name << "喵\n"; } }; // 机器人 class Robot : public Toy { public: Robot(const std::string& name) : Toy(name, "机器人") {} void special() override { std::cout << name << " 颗粒感\n"; } };
ToyFactory.hpp
#pragma once #include "Toy.hpp" class ToyFactory { public: ~ToyFactory() { for (auto p : toys) delete p; } void add(Toy* toy) { toys.push_back(toy); } void show_all() const { for (auto t : toys) { t->info(); t->special(); std::cout << "---------------------\n"; } } private: std::vector<Toy*> toys; };
demo4.cpp
#include "ToyFactory.hpp" int main() { ToyFactory factory; factory.add(new Bear("熊大")); factory.add(new Cat("小花猫")); factory.add(new Robot("小R")); factory.show_all(); return 0; }
运行结果

浙公网安备 33010602011771号