实验6
实验任务1:
contestant.hpp:
1 #pragma once 2 #include <iomanip> 3 #include <iostream> 4 #include <string> 5 6 struct Contestant 7 { 8 long id; // 学号 9 std::string name; // 姓名 10 std::string major; // 专业 11 int solved; // 解题数 12 int penalty; // 总罚时 13 }; 14 15 // 重载<< 16 // 要求:姓名/专业里不含空白符 17 inline std::ostream &operator<<(std::ostream &out, const Contestant &c) 18 { 19 out << std::left; 20 out << std::setw(15) << c.id 21 << std::setw(15) << c.name 22 << std::setw(15) << c.major 23 << std::setw(10) << c.solved 24 << std::setw(10) << c.penalty; 25 26 return out; 27 } 28 29 // 重载>> 30 inline std::istream &operator>>(std::istream &in, Contestant &c) 31 { 32 in >> c.id >> c.name >> c.major >> c.solved >> c.penalty; 33 34 return in; 35 }
utils.hpp:
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 { 12 if (a.solved != b.solved) 13 return a.solved > b.solved; 14 15 return a.penalty < b.penalty; 16 } 17 18 // 将结果写至任意输出流 19 inline void write(std::ostream &os, const std::vector<Contestant> &v) 20 { 21 for (const auto &x : v) 22 os << x << '\n'; 23 } 24 25 // 将结果打印到屏幕 26 inline void print(const std::vector<Contestant> &v) 27 { 28 write(std::cout, v); 29 } 30 31 // 将结果保存到文件 32 inline void save(const std::string &filename, const std::vector<Contestant> &v) 33 { 34 std::ofstream os(filename); 35 if (!os) 36 throw std::runtime_error("fail to open " + filename); 37 38 write(os, v); 39 } 40 41 // 从文件读取信息(跳过标题行) 42 inline std::vector<Contestant> load(const std::string &filename) 43 { 44 std::ifstream is(filename); 45 if (!is) 46 throw std::runtime_error("fail to open " + filename); 47 48 std::string line; 49 std::getline(is, line); // 跳过标题 50 51 std::vector<Contestant> v; 52 Contestant t; 53 int seq; 54 while (is >> seq >> t) 55 v.push_back(t); 56 57 return v; 58 }
task1.cpp:
1 #include <algorithm> 2 #include <iostream> 3 #include <stdexcept> 4 #include <vector> 5 #include "contestant.hpp" 6 #include "utils.hpp" 7 #include "windows.h" 8 9 const std::string in_file = "./data.txt"; 10 const std::string out_file = "./ans.txt"; 11 12 void app() 13 { 14 std::vector<Contestant> contestants; 15 16 try 17 { 18 contestants = load(in_file); 19 std::sort(contestants.begin(), contestants.end(), cmp_by_solve); 20 print(contestants); 21 save(out_file, contestants); 22 } 23 catch (const std::exception &e) 24 { 25 std::cerr << e.what() << '\n'; 26 return; 27 } 28 } 29 30 int main() 31 { 32 SetConsoleOutputCP(CP_UTF8); 33 app(); 34 }
运行结果:

数据文件ans.txt:
问题回答:
1.(1)std::cout 是 std::ostream 的直接实例,std::ofstream 继承自 std::ostream,
std::ostream& 作为参数类型时,能接收任何 std::ostream 派生类的对象,因此write()能同时接受 std::cout 和 std::ofstream 对象作为实参。
(2)不需要。只要该设备也提供 std::ostream 接口就能调用write()。
2.(1)
第一处:
1 inline void save(const std::string &filename, const std::vector<Contestant> &v) 2 { 3 std::ofstream os(filename); 4 if (!os) 5 throw std::runtime_error("fail to open " + filename); 6 7 write(os, v); 8 }
抛出异常情况:打开指定文件(out_file)失败时。
第二处:
1 inline std::vector<Contestant> load(const std::string &filename) 2 { 3 std::ifstream is(filename); 4 if (!is) 5 throw std::runtime_error("fail to open " + filename); 6 7 std::string line; 8 std::getline(is, line); // 跳过标题 9 10 std::vector<Contestant> v; 11 Contestant t; 12 int seq; 13 while (is >> seq >> t) 14 v.push_back(t); 15 16 return v; 17 }
抛出异常情况:打开指定输入文件(in_file)失败时。
(2)被try{}catch{}捕获,通过std::cerr << e.what() << '\n';进行输出,并终止程序。
3.可以,功能、性能、结果一致,都无额外开销。
4.(1)

问题:读取不完整,输出产生乱码;
原因:is >> seq >> t 读取时,solved和penalty 无值,会导致读取失败,导致while循环终止,无法继续读取。
(2)
1 inline std::vector<Contestant> load(const std::string &filename) 2 { 3 std::ifstream is(filename); 4 if (!is) 5 throw std::runtime_error("fail to open " + filename); 6 7 std::string line; 8 std::getline(is, line); // 跳过标题 9 10 std::vector<Contestant> v; 11 Contestant t; 12 int seq; 13 int line_num = 1; 14 while(getline(is, line)) 15 { 16 line_num++; 17 std::istringstream iss(line); 18 if(line.empty()||line.find_first_not_of(" \t\n\r") == std::string::npos) continue; 19 if (!(iss >> seq >> t.id >> t.name >> t.major >> t.solved >> t.penalty)) 20 { 21 std::cerr <<"Warning: invalid data format at line " << line_num << ", skipped.\n"; 22 continue; 23 } 24 v.push_back(t); 25 } 26 return v; 27 }
实验任务2:
student.hpp:
1 #pragma once 2 3 #include <iostream> 4 #include <string> 5 6 class Student 7 { 8 public: 9 Student() = default; 10 ~Student() = default; 11 12 const std::string get_major() const; 13 int get_grade() const; 14 15 friend std::ostream &operator<<(std::ostream &os, const Student &s); 16 friend std::istream &operator>>(std::istream &is, Student &s); 17 18 private: 19 int id; 20 std::string name; 21 std::string major; 22 int grade; // 0-100 23 };
student.cpp:
1 #include "student.hpp" 2 #include <iomanip> 3 #include <iostream> 4 5 std::ostream &operator<<(std::ostream &os, const Student &s) 6 { 7 os << std::left; 8 os << std::setw(15) << s.id 9 << std::setw(15) << s.name 10 << std::setw(15) << s.major 11 << std::setw(15) << s.grade; 12 return os; 13 } 14 15 std::istream &operator>>(std::istream &is, Student &s) 16 { 17 int temp_id; 18 std::string temp_name; 19 std::string temp_major; 20 int temp_grade; 21 if(!(is >> temp_id >> temp_name >> temp_major >> temp_grade)) 22 throw std::runtime_error("Invalid input format for Student"); 23 if(temp_grade < 0 || temp_grade > 100) 24 throw std::runtime_error("Grade must be between 0 and 100"); 25 s.id = temp_id; 26 s.name = temp_name; 27 s.major = temp_major; 28 s.grade = temp_grade; 29 return is; 30 } 31 32 const std::string Student::get_major() const 33 { 34 return major; 35 } 36 37 int Student::get_grade() const 38 { 39 return grade; 40 }
stumgr.hpp:
1 #pragma once 2 #include <string> 3 #include <vector> 4 #include "student.hpp" 5 6 class StuMgr 7 { 8 public: 9 void load(const std::string &file); // 加载数据文件(空格分隔) 10 void sort(); // 排序: 按专业字典序升序、同专业分数降序 11 void print() const; // 打印到屏幕 12 void save(const std::string &file) const; // 保存到文件 13 14 private: 15 void write(std::ostream &os) const; // 把数据写到任意输出流 16 17 private: 18 std::vector<Student> students; 19 };
stumgr.cpp:
1 #include "stumgr.hpp" 2 #include <fstream> 3 #include <algorithm> 4 #include <iostream> 5 #include <sstream> 6 7 void StuMgr::load(const std::string &filename) 8 { 9 std::ifstream is(filename); 10 if (!is) 11 throw std::runtime_error("fail to open " + filename); 12 13 std::string line; 14 getline(is, line); 15 16 int line_num = 1; 17 while (getline(is, line)) 18 { 19 std::istringstream iss(line); 20 line_num++; 21 if (line.empty() || line.find_first_not_of(" \t\n\r") == std::string::npos) 22 { 23 std::cerr << "[Warning] line " << line_num << " format error, skipped: "; 24 std::cout << line << '\n'; 25 continue; 26 } 27 else 28 { 29 int temp_id; 30 std::string temp_name; 31 std::string temp_major; 32 int temp_grade; 33 if (!(iss >> temp_id >> temp_name >> temp_major >> temp_grade)) 34 { 35 std::cerr << "[Warning] line " << line_num << " format error, skipped: "; 36 std::cout << line << '\n'; 37 continue; 38 } 39 else if (temp_grade < 0 || temp_grade > 100) 40 { 41 std::cerr << "[Warning] line " << line_num << " grade invalid, skipped: "; 42 std::cout << line << '\n'; 43 continue; 44 } 45 else 46 { 47 { 48 Student s; 49 std::istringstream line_iss(line); 50 try 51 { 52 line_iss >> s; 53 } 54 catch (const std::runtime_error &e) 55 { 56 std::cerr << "[Warning] line " << line_num << " " << e.what() << ", skipped: "; 57 std::cout << line << '\n'; 58 continue; 59 } 60 students.push_back(s); 61 } 62 } 63 } 64 } 65 } 66 67 void StuMgr::sort() 68 { 69 std::sort(students.begin(), students.end(), [](const Student &a, const Student &b) 70 { 71 if (a.get_major() != b.get_major()) 72 return a.get_major() < b.get_major(); 73 else 74 return a.get_grade() > b.get_grade(); }); 75 } 76 77 void StuMgr::print() const 78 { 79 write(std::cout); 80 } 81 82 void StuMgr::save(const std::string &filename) const 83 { 84 std::ofstream os(filename); 85 if (!os) 86 throw std::runtime_error("fail to open " + filename); 87 88 write(os); 89 } 90 91 void StuMgr::write(std::ostream &os) const 92 { 93 for (const auto &s : students) 94 { 95 os << s << '\n'; 96 } 97 }
task2.cpp:
1 #include <iostream> 2 #include <limits> 3 #include <string> 4 #include "stumgr.hpp" 5 #include "Windows.h" 6 7 const std::string in_file = "./data_bad.txt"; 8 const std::string out_file = "./ans.txt"; 9 10 void menu() 11 { 12 std::cout << "\n**********简易应用**********\n" 13 "1. 加载文件\n" 14 "2. 排序\n" 15 "3. 打印到屏幕\n" 16 "4. 保存到文件\n" 17 "5. 退出\n" 18 "请选择:"; 19 } 20 21 void app() 22 { 23 StuMgr mgr; 24 25 while (true) 26 { 27 menu(); 28 int choice; 29 std::cin >> choice; 30 31 try 32 { 33 switch (choice) 34 { 35 case 1: 36 mgr.load(in_file); 37 std::cout << "加载成功\n"; 38 break; 39 case 2: 40 mgr.sort(); 41 std::cout << "排序已完成\n"; 42 break; 43 case 3: 44 mgr.print(); 45 std::cout << "打印已完成\n"; 46 break; 47 case 4: 48 mgr.save(out_file); 49 std::cout << "导出成功\n"; 50 break; 51 case 5: 52 return; 53 default: 54 std::cout << "不合法输入\n"; 55 } 56 } 57 catch (const std::exception &e) 58 { 59 std::cout << "Error: " << e.what() << '\n'; 60 } 61 } 62 } 63 64 int main() 65 { 66 SetConsoleOutputCP(CP_UTF8); 67 app(); 68 }
运行结果:



浙公网安备 33010602011771号