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

问题一:
std::string course_name;记录课程的名称
std::vector<int> grades;记录下每个人的成绩
std::array<int,5> counts;记录5个分数段各自的人数
std::array<double,5> rates;记录5个分数段各自的人数占比
问题二:
不合法, grades是私有类型
问题三:
(1)一次,判断整体的打印信息是否有修改
(2)需要,打印信息改变
问题四:
直接在info函数中添加,
int count = grades.size()/2 ;
if(grades.size()%2 == 0){
std::cout<<(gardes[count - 1] +grades[count])/2.0<<std::endl;
}
else{
std::cout<<grade[count]/2.0<<std::endl;
}
问题五:
不能,再次统计时
问题六:
(1)无
(2)有,避免元素复制
任务二:
GradeCalc.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); // 录入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; // 保存各分数段人数([0, 60), [60, 70), [70, 80), [80, 90), [90, 100] 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 "GradeCalc1.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 = static_cast<int>(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 (size_t i = 0; i < rates.size(); ++i) rates[i] = counts[i] * 1.0 / this->size(); is_dirty = false; }
test2.cpp
1 #include <iostream> 2 #include <string> 3 #include "GradeCalc1.hpp" 4 5 void test() { 6 GradeCalc c1("OOP"); 7 8 std::cout << "录入成绩:\n"; 9 c1.input(5); 10 11 std::cout << "输出成绩:\n"; 12 c1.output(); 13 14 std::cout << "排序后成绩:\n"; 15 c1.sort(); c1.output(); 16 17 std::cout << "*************成绩统计信息*************\n"; 18 c1.info(); 19 20 } 21 22 int main() { 23 test(); 24 }

问题一:
class GradeCalc:private std::vector<int>;
问题二:
会,不能,私有继承
问题三:
组合方式在内部通过grades接口进行访问。
继承方式在内部用this指针直接通过使用基类的接口来进行访问。
问题四:
组合,安全高效
任务三:
Graph.hpp
1 #pragma once 2 3 #include <string> 4 #include <vector> 5 6 enum class GraphType { circle, triangle, rectangle }; 7 8 // Graph类定义 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 40 private: 41 std::vector<Graph*> graphs; 42 }; 43 44 // 4. 工具函数 45 GraphType str_to_GraphType(const std::string& s); // 字符串转枚举类型 46 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 // Circle类实现 9 void Circle::draw() { std::cout << "draw a circle...\n"; } 10 11 // Triangle类实现 12 void Triangle::draw() { std::cout << "draw a triangle...\n"; } 13 14 // Rectangle类实现 15 void Rectangle::draw() { std::cout << "draw a rectangle...\n"; } 16 17 // Canvas类实现 18 void Canvas::add(const std::string& type) { 19 Graph* g = make_graph(type); 20 if (g) 21 graphs.push_back(g); 22 } 23 24 void Canvas::paint() const { 25 for (Graph* g : graphs) 26 g->draw(); 27 } 28 29 Canvas::~Canvas() { 30 for (Graph* g : graphs) 31 delete g; 32 } 33 34 // 工具函数实现 35 // 字符串 → 枚举转换 36 GraphType str_to_GraphType(const std::string& s) { 37 std::string t = s; 38 std::transform(s.begin(), s.end(), t.begin(), 39 [](unsigned char c) { return std::tolower(c); }); 40 41 if (t == "circle") 42 return GraphType::circle; 43 44 if (t == "triangle") 45 return GraphType::triangle; 46 47 if (t == "rectangle") 48 return GraphType::rectangle; 49 50 return GraphType::circle; // 缺省返回 51 } 52 53 // 创建图形,返回堆对象指针 54 Graph* make_graph(const std::string& type) { 55 switch (str_to_GraphType(type)) { 56 case GraphType::circle: return new Circle; 57 case GraphType::triangle: return new Triangle; 58 case GraphType::rectangle: return new Rectangle; 59 default: return nullptr; 60 } 61 }
test3.cpp
1 #include <string> 2 #include "Graph.hpp" 3 4 void test() { 5 Canvas canvas; 6 7 canvas.add("circle"); 8 canvas.add("triangle"); 9 canvas.add("rectangle"); 10 canvas.paint(); 11 } 12 13 int main() { 14 test(); 15 }

问题一:
(1)std::vector<Graph*> graphs,表示不同的图形。
(2)class Circle:public Graph;
class Triangle:public Graph;
class Rectangle:public Graph
问题二:
(1)无输出结果
(2)报错
(3)内存泄漏
问题三:
Graph.hpp类声明、enum添加
Graph.cpp类定义
问题四:
(1)Canvas调用析构函数时
(2)利:比智能指针更简单,且节省内存;
弊:原始指针需要自己写new/delete,容易出现内存泄漏
任务四:
功能:玩具名的查找、玩具类型的查找、玩具功能的查找、添加玩具、删除玩具
使用场景:工厂对玩具的统计与查找
ToyFactory类与Toy类组合,便于整理与查找
Toy.hpp
1 #include<string> 2 #include<vector> 3 enum kind {name,type,function }; 4 5 class Toy { 6 public: 7 Toy(const std::string& name, const std::string& type, const std::string& function); 8 Toy(const Toy& x); 9 ~Toy(); 10 const std::string& get_name()const; 11 const std::string& get_type()const; 12 const std::string& get_function()const; 13 void display()const; 14 private: 15 std::string toy_name; 16 std::string toy_type; 17 std::string toy_function; 18 }; 19 20 class ToyFactory { 21 public: 22 void add(const std::string& name, const std::string& type,const std::string& function); 23 void remove(const std::string& name); 24 bool find(const std::string& name,int func = 0 ) const; 25 void display() const; 26 size_t size() const; 27 private: 28 std::vector<int> index(const std::string &name, int func = 0) const; 29 void sort(); 30 private: 31 std::vector <Toy> toys; 32 33 };
Toy.cpp
1 #include<iostream> 2 #include<string> 3 #include<vector> 4 #include<algorithm> 5 #include"Toy.hpp" 6 7 8 Toy::Toy(const std::string& name, const std::string& type, const std::string& function) : toy_name{ name }, toy_type{ type }, toy_function{function} {}; 9 10 Toy::Toy(const Toy& x) :toy_name{ x.toy_name }, toy_type{ x.toy_type }, toy_function{x.toy_function} {}; 11 12 Toy::~Toy() {}; 13 14 const std::string& Toy::get_name()const { 15 return toy_name; 16 } 17 18 const std::string& Toy::get_type() const{ 19 return toy_type; 20 } 21 22 const std::string& Toy::get_function() const { 23 return toy_function; 24 } 25 26 void Toy::display()const { 27 std::cout << toy_name << " , " << toy_type <<" , "<<toy_function<< std::endl; 28 } 29 void ToyFactory::add(const std::string& name, const std::string& type,const std::string &function) { 30 if (index(name).size() == 0) { 31 toys.push_back(Toy(name, type, function)); 32 sort(); 33 return; 34 } 35 else { 36 std::cout <<name<< "已经存在" << std::endl; 37 } 38 } 39 40 void ToyFactory::remove(const std::string& name) { 41 std::vector<int> i = index(name); 42 if (i.size() == 0) { 43 std::cout <<name<< "不存在" << std::endl; 44 return; 45 } 46 else { 47 for (auto j : i) { 48 toys.erase(toys.begin() + j); 49 } 50 std::cout << "已移除" << name << std::endl; 51 } 52 } 53 54 bool ToyFactory::find(const std::string &name,int func) const { 55 std::vector<int> i = index(name,func); 56 if (i.size() == 0) { 57 std::cout << "未找到" << name << std::endl; 58 return false; 59 } 60 else { 61 for (auto j : i) { 62 toys[j].display(); 63 } 64 } 65 return true; 66 } 67 68 void ToyFactory::display() const{ 69 for (auto& i : toys) { 70 i.display(); 71 } 72 } 73 74 size_t ToyFactory::size() const{ 75 return toys.size(); 76 } 77 78 std::vector<int> ToyFactory::index(const std::string &name,int func)const { 79 std::vector<int> count; 80 int counts = 0; 81 for (const auto& i : toys) { 82 if (i.get_name() == name&&func == 0) { 83 count.push_back(counts); 84 } 85 else if (i.get_type() == name && type == 1) { 86 count.push_back(counts); 87 } 88 else if (i.get_function() == name && func == 2) { 89 count.push_back(counts); 90 } 91 counts++; 92 } 93 return count; 94 } 95 96 void ToyFactory::sort() { 97 std::sort(toys.begin(), toys.end(), [](const Toy& a, const Toy& b) { 98 return a.get_name() < b.get_name(); 99 }); 100 }
test4.cpp
1 #include<iostream> 2 #include"Toy.hpp" 3 4 void test() { 5 ToyFactory toys; 6 std::cout << "添加玩具" << std::endl; 7 toys.add("Elysia", "badge","pendant"); 8 toys.add("Kiana", "cushion","household_supplies"); 9 toys.add("Bronya", "model","decoration"); 10 toys.add("FeiXiao", "sign","ornament"); 11 std::cout << "共有" << toys.size() << "个玩具" << std::endl; 12 toys.display(); 13 std::cout << "查找玩具(名称)" << std::endl; 14 toys.find("Elysia"); 15 toys.find("Kiana"); 16 std::cout << "查找玩具(类型)" << std::endl; 17 toys.find("model",1); 18 std::cout << "查找玩具(功能)" << std::endl; 19 toys.find("ornament",2); 20 std::cout << "删除玩具" << std::endl; 21 toys.remove("FeiXiao"); 22 toys.remove("WangTY"); 23 24 } 25 26 int main() { 27 test(); 28 }


浙公网安备 33010602011771号