实验6

contestant.hpp

 1 #pragma once
 2 #include <iomanip>
 3 #include <iostream>
 4 #include <string>
 5 
 6 struct Contestant {
 7     long   id;              // 学号
 8     std::string name;       // 姓名
 9     std::string major;      // 专业
10     int    solved;          // 解题数
11     int    penalty;         // 总罚时
12 };
13 
14 // 重载<<
15 // 要求:姓名/专业里不含空白符
16 inline std::ostream& operator<<(std::ostream& out, const Contestant& c) {
17     out << std::left;
18     out << std::setw(15) << c.id
19         << std::setw(15) << c.name
20         << std::setw(15) << c.major
21         << std::setw(10) << c.solved
22         << std::setw(10) << c.penalty;
23 
24     return out;
25 }
26 
27 // 重载>>
28 inline std::istream& operator>>(std::istream& in, Contestant& c) {
29     in >> c.id >> c.name >> c.major >> c.solved >> c.penalty;
30 
31     return in;
32 }

utils.cpp

 1 #pragma once
 2 #include <fstream>
 3 #include <iostream>
 4 #include <stdexcept>
 5 #include <string>
 6 #include <vector>
 7 #include "contestant.hpp"
 8 
 9 // ACM 排序规则:先按解题数降序,再按罚时升序
10 inline bool cmp_by_solve(const Contestant& a, const Contestant& b) {
11     if(a.solved != b.solved)
12         return a.solved > b.solved;
13     
14     return a.penalty < b.penalty;
15 }
16 
17 // 将结果写至任意输出流
18 inline void write(std::ostream& os, const std::vector<Contestant>& v) {
19     for (const auto& x : v) 
20         os << x << '\n';
21 }
22 
23 // 将结果打印到屏幕
24 inline void print(const std::vector<Contestant>& v) {
25     write(std::cout, v);
26 }
27 
28 // 将结果保存到文件
29 inline void save(const std::string& filename, const std::vector<Contestant>& v) {
30     std::ofstream os(filename);
31     if (!os) 
32         throw std::runtime_error("fail to open " + filename);
33 
34     write(os, v);
35 }
36 
37 // 从文件读取信息(跳过标题行)
38 inline std::vector<Contestant> load(const std::string& filename) {
39     std::ifstream is(filename);
40     if (!is) 
41         throw std::runtime_error("fail to open " + filename);
42 
43     std::string line;
44     std::getline(is, line);          // 跳过标题
45 
46     std::vector<Contestant> v;
47     Contestant t;
48     int seq;
49     while (is >> seq >> t) 
50         v.push_back(t);
51         
52     return v;
53 }

task.cpp

 1 #include <algorithm>
 2 #include <iostream>
 3 #include <stdexcept>
 4 #include <vector>
 5 #include "contestant.hpp"
 6 #include "utils.hpp"
 7 
 8 const std::string in_file = "./data.txt";
 9 const std::string out_file = "./ans.txt";
10 
11 void app() {
12     std::vector<Contestant> contestants;
13 
14     try {
15         contestants = load(in_file);                                      
16         std::sort(contestants.begin(), contestants.end(), cmp_by_solve); 
17         print(contestants);      
18         save(out_file, contestants);                         
19     } catch (const std::exception& e) {
20         std::cerr << e.what() << '\n';
21         return;
22     }
23 }
24 
25 int main() {
26     app();
27 }

屏幕截图 2025-12-23 222529

屏幕截图 2025-12-23 222554

问题1:(1)std::ostream是std::cout和std::ofstream的基类,std::ostream类型的引用可以绑定到这两个派生类,所以可以同时接受。
(2)不需要改动write()。

问题2:第一处:save函数line 32,当保存文件时文件无法打开会throw运行时错误:“throw std::runtime_error("fail to open " + filename);”,在app函数可以被捕获,先进行输出,随后直接退出app函数,程序终止;;第二处为文件读取信息load,其作用于前者相似,依旧是在app捕获。

问题3:可以换成给出的lambda表达式,功能、性能、结果均一致。个人认为此处使用lambda表达式会导致代码可读性降低一些,不太适合。
问题4:输出结果如下
屏幕截图 2025-12-23 222906

实验2

student.hpp

 1 #pragma once
 2 
 3 #include <iostream>
 4 #include <string>
 5 #include <iomanip>
 6 
 7 class Student {
 8 public:
 9     Student() = default;
10     Student(int id0, std::string name0, std::string major0, int grade0);
11     ~Student() = default;
12     
13     const std::string get_major() const;
14     int get_grade() const;
15 
16     friend std::ostream& operator<<(std::ostream& os, const Student& s);
17     friend std::istream& operator>>(std::istream& is, Student& s);
18 
19 private:
20     int id;   
21     std::string  name;
22     std::string  major;
23     int          grade;  // 0-100
24 };

student.cpp

 1 #include "student.hpp"
 2 
 3 Student::Student(int id0, std::string name0, std::string major0, int grade0) : id{ id0 }, name{ name0 }, major{ major0 }, grade{ grade0 } {}
 4 
 5 const std::string Student::get_major() const
 6 {
 7     return major;
 8 }
 9 
10 int Student::get_grade() const
11 {
12     return grade;
13 }
14 
15 std::ostream& operator<<(std::ostream& os, const Student& s)
16 {
17     os << std::left;
18     os << std::setw(15) << s.id;
19     os << std::setw(15) << s.name;
20     os << std::setw(15) << s.major;
21     os << std::setw(15) << s.grade;
22     return os;
23 }
24 
25 std::istream& operator>>(std::istream& is, Student& s)
26 {
27     is >> s.id >> s.name >> s.major >> s.grade;
28     return is;
29 }

stumgr.hpp

 1 #pragma once
 2 #include <string>
 3 #include <vector>
 4 #include <fstream>
 5 #include <sstream>
 6 #include <algorithm>
 7 #include "student.hpp"
 8 
 9 class StuMgr {
10 public:
11     void load(const std::string& file);  // 加载数据文件(空格分隔)
12     void sort();                         // 排序: 按专业字典序升序、同专业分数降序
13     void print() const;                  // 打印到屏幕
14     void save(const std::string& file) const; // 保存到文件
15 
16 private:
17     void write(std::ostream &os) const;  // 把数据写到任意输出流
18 
19 private:
20     std::vector<Student> students;
21 };

stumgr.cpp

 1 #include "stumgr.hpp"
 2 
 3 bool StuCheckBoundary(int id, int grade)
 4 {
 5     if (id < 1000 || id > 1100)
 6     {
 7         //std::cerr << "invalid ID: " << id << std::endl;
 8         return false;
 9     }
10     if (grade < 0 || grade > 100)
11     {
12         //std::cerr << "invalid grade: " << grade << std::endl;
13         return false;
14     }
15     return true;
16 }
17 
18 void StuMgr::load(const std::string& file)
19 {
20     std::ifstream ifs(file);
21     if (!ifs)
22     {
23         throw std::runtime_error("fail to load" + file);
24         std::cerr << "[ERROR]FILE LOAD FAIL\n";
25     }
26 
27     std::string trash_line;
28     std::getline(ifs, trash_line);
29 
30     std::string line;
31     int linenum = 0;
32     while (std::getline(ifs, line))
33     {
34         std::istringstream iss(line);
35         linenum++;
36         int id;
37         std::string name;
38         std::string major;
39         int grade;
40         iss >> id >> name >> major >> grade;
41         if (iss.fail() || !iss.eof())
42         {
43             std::cerr << "[ERROR] LINE " << linenum << " FORMAT WRONG\n";
44             //throw std::runtime_error("[ERROR] LINE " + std::to_string(linenum) + " FORMAT WRONG");
45             continue;
46         }//解析失败或者字段过少会触发fail, 剩余字段过多会触发eof()即解析完后流中还有剩余数据
47 
48         if (!StuCheckBoundary(id, grade))
49         {
50             std::cerr << "[ERROR] LINE " << linenum << " DATA OUT OF RANGE\n";
51             //throw std::runtime_error("[ERROR] LINE " + std::to_string(linenum) + " DATA OUT OF RANGE");
52             continue;
53         }
54 
55         students.emplace_back(id, name, major, grade);
56     }
57 
58 }
59 
60 inline bool cmp_stu(const Student& a, const Student& b)
61 {
62     if (a.get_major() != b.get_major())
63         return a.get_major() < b.get_major();
64     return a.get_grade() > b.get_grade();
65 }
66 
67 void StuMgr::sort()
68 {
69     std::sort(students.begin(), students.end(), cmp_stu);
70 }
71 
72 void StuMgr::print() const
73 {
74     write(std::cout);
75 }
76 
77 void StuMgr::save(const std::string& file) const
78 {
79     std::ofstream os(file);
80     if (!os)
81     {
82         std::cerr << "[ERROR]FILE OPEN FAIL\n";
83         throw std::runtime_error("fail to open" + file);
84     }
85     write(os);
86 }
87 
88 void StuMgr::write(std::ostream& os) const
89 {
90     for (const auto& stu : students)
91     {
92         os << stu << '\n';
93     }
94 }

task.cpp

 1 #include <iostream>
 2 #include <limits>
 3 #include <string>
 4 #include "stumgr.hpp"
 5 
 6 const std::string in_file = "./data_bad.txt";
 7 const std::string out_file = "./ans.txt";
 8 
 9 void menu() {
10     std::cout << "\n**********简易应用**********\n"
11                  "1. 加载文件\n"
12                  "2. 排序\n"
13                  "3. 打印到屏幕\n"
14                  "4. 保存到文件\n"
15                  "5. 退出\n"
16                  "请选择:";
17 }
18 
19 void app() {
20     StuMgr mgr;
21 
22     while(true) {
23         menu();
24         int choice;
25         std::cin >> choice;
26 
27         try {
28             switch (choice) {
29             case 1: mgr.load(in_file); 
30                     std::cout << "加载成功\n"; break;
31             case 2: mgr.sort(); 
32                     std::cout << "排序已完成\n"; break;
33             case 3: mgr.print(); 
34                     std::cout << "打印已完成\n"; break;
35             case 4: mgr.save(out_file); 
36                     std::cout << "导出成功\n"; break;
37             case 5: return;
38             default: std::cout << "不合法输入\n";
39             }
40         }
41         catch (const std::exception& e) {
42             std::cout << "Error: " << e.what() << '\n';
43         }
44     }
45 }
46 
47 int main() {
48     app();
49 }

屏幕截图 2025-12-23 223346

屏幕截图 2025-12-23 223351

屏幕截图 2025-12-23 223445

 


posted @ 2025-12-23 22:37  zhj910  阅读(2)  评论(0)    收藏  举报