实验6 模板类、文件I/O和异常处理
实验任务一
1 #pragma once 2 3 #include <iostream> 4 #include <stdexcept> 5 6 // 声明 7 //////////////////////////////////////////////////// 8 // 复数模板类声明 9 template<typename T> 10 class Complex { 11 public: 12 Complex(T r = 0, T i = 0); 13 Complex(const Complex<T>& c); 14 15 T get_real() const; 16 T get_imag() const; 17 18 // 重载+=为成员函数 19 Complex<T>& operator+=(const Complex<T>& c); 20 21 // 重载<<、>>为友元函数 22 template<typename T1> 23 friend std::ostream& operator<<(std::ostream& out, const Complex<T1>& c); 24 25 template<typename T1> 26 friend std::istream& operator>>(std::istream& in, Complex<T1>& c); 27 28 private: 29 T real, imag; 30 }; 31 32 // 普通函数声明 33 // 重载+用于Complex类型 34 template<typename T> 35 Complex<T> operator+(const Complex<T>& c1, const Complex<T>& c2); 36 37 // 重载==用于Complex类型 38 template<typename T> 39 bool operator==(const Complex<T>& c1, const Complex<T>& c2); 40 41 42 // 实现 43 //////////////////////////////////////////////////// 44 // 成员函数模板实现 45 template<typename T> 46 Complex<T>::Complex(T r, T i) : real{ r }, imag{ i } { 47 } 48 49 template<typename T> 50 Complex<T>::Complex(const Complex<T>& c) : real{ c.real }, imag{ c.imag } { 51 } 52 53 template<typename T> 54 T Complex<T>::get_real() const { 55 return real; 56 } 57 58 template<typename T> 59 T Complex<T>::get_imag() const { 60 return imag; 61 } 62 63 // 重载+=为成员函数 64 template<typename T> 65 Complex<T>& Complex<T>::operator+=(const Complex<T>& c) { 66 real += c.real; 67 imag += c.imag; 68 69 return *this; 70 } 71 72 /////////////////////////////////////// 73 // 友元函数模板实现 74 template<typename T1> 75 std::ostream& operator<<(std::ostream& out, const Complex<T1>& c) { 76 if (c.imag >= 0) 77 out << c.real << " + " << c.imag << "i"; 78 else 79 out << c.real << " - " << -c.imag << "i"; 80 81 return out; 82 } 83 84 template<typename T1> 85 std::istream& operator>>(std::istream& in, Complex<T1>& c) { 86 in >> c.real >> c.imag; 87 88 return in; 89 } 90 91 /////////////////////////////////////// 92 // 普通函数模板实现 93 // 重载+用于Complex类型 94 template<typename T> 95 Complex<T> operator+(const Complex<T>& c1, const Complex<T>& c2) { 96 return Complex<T>(c1.get_real() + c2.get_real(), 97 c1.get_imag() + c2.get_imag()); 98 } 99 100 // 重载==用于Complex类型 101 template<typename T> 102 bool operator==(const Complex<T>& c1, const Complex<T>& c2) { 103 return c1.get_real() == c2.get_real() && 104 c1.get_imag() == c2.get_imag(); 105 }
(最后一行&&应改为==)
1 #include "Complex.hpp" 2 #include <iostream> 3 #include <fstream> 4 #include <stdexcept> 5 6 void test1(); 7 void test2(); 8 9 int main() { 10 using namespace std; 11 12 cout << "测试1: 复数模板类测试" << endl; 13 test1(); 14 15 cout << "\n测试2: 文件I/O测试" << endl; 16 test2(); 17 } 18 19 void test1() { 20 using namespace std; 21 22 Complex<double> c1{ 3.5, 2 }, c2; 23 cout << "Enter c2: "; 24 cin >> c2; 25 cout << "c1 = " << c1 << endl; 26 cout << "c2 = " << c2 << endl; 27 cout << "c1 == c2: " << boolalpha << (c1 == c2) << endl; 28 29 cout << "c1 + c2 = " << c1 + c2 << endl; 30 c1 += c2; 31 cout << "c1.real = " << c1.get_real() << endl; 32 cout << "c1.imag = " << c1.get_imag() << endl; 33 34 cout << "c1 == c2: " << boolalpha << (c1 == c2) << endl; 35 } 36 37 void test2() { 38 using namespace std; 39 40 Complex<int> c1{ 1, 2 }, c2{ 9, -7 }; 41 ofstream out("ans.txt"); 42 if (!out.is_open()) { 43 cout << "fail to open file ans.txt to write\n"; 44 return; 45 } 46 47 out << "c1 = " << c1 << endl; 48 out << "c2 = " << c2 << endl; 49 out << "c1 + c2 = " << c1 + c2 << endl; 50 out << "(c1 == c2) = " << boolalpha << (c1 == c2) << endl; 51 52 out.close(); 53 cout << "测试ok!" << endl; 54 }
实验任务二
1 #include "Contestant.hpp" 2 #include "utils.hpp" 3 #include <iostream> 4 #include <vector> 5 #include <algorithm> 6 7 8 void test() { 9 using namespace std; 10 11 vector<Contestant> v; 12 13 load("data2.txt", v); // 从文件加载选手信息到对象v 14 sort(v.begin(), v.end(), compare_by_solutionInfo); // 按解题情况排序 15 output(cout, v); // 输出对象v中信息到屏幕 16 save("ans.txt", v); // 把对象v中选手信息保存到文件 17 } 18 19 int main() { 20 test(); 21 }
1 #pragma once 2 3 #include <iostream> 4 #include <iomanip> 5 #include <string> 6 7 using std::string; 8 using std::ostream; 9 using std::istream; 10 using std::setw; 11 using std::setprecision; 12 using std::setiosflags; 13 using std::ios_base; 14 15 // Contestant类声明 16 class Contestant { 17 public: 18 Contestant() = default; 19 ~Contestant() = default; 20 21 int get_num() const { return num; } 22 float get_time_usage() const { return time_usage; } 23 24 friend ostream& operator<<(ostream& out, const Contestant& c); 25 friend istream& operator>>(istream& in, Contestant& c); 26 27 private: 28 string no; // 学号 29 string name; // 姓名 30 string major; // 专业 31 int num; // 解题数 32 float time_usage; // 总用时 33 }; 34 35 // 友元函数实现 36 // 重载流插入运算符<< 37 ostream& operator<<(ostream& out, const Contestant& c) { 38 out << setiosflags(ios_base::left); 39 out << setw(15) << c.no 40 << setw(15) << c.name 41 << setw(15) << c.major 42 << setw(5) << c.num 43 << setprecision(2) << c.time_usage; 44 45 return out; 46 } 47 48 // 重载流提取运算符>> 49 istream& operator>>(istream& in, Contestant& c) { 50 in >> c.no >> c.name >> c.major >> c.num >> c.time_usage; 51 52 return in; 53 }
1 #pragma once 2 3 #include "Contestant.hpp" 4 #include <fstream> 5 #include <iostream> 6 #include <string> 7 #include <vector> 8 9 // 排序函数 10 // 按解题数比较,解题数相同的情况下,按总用时比较,总用时越少,排名越靠前 11 bool compare_by_solutionInfo(const Contestant& c1, const Contestant& c2) { 12 if (c1.get_num() > c2.get_num()) 13 return true; 14 15 if (c1.get_num() == c2.get_num()) 16 return c1.get_time_usage() < c2.get_time_usage(); 17 18 return false; 19 } 20 21 // 把vector<Constestant>对象中的元素插入到输出流out 22 void output(std::ostream& out, const std::vector<Contestant>& v) { 23 for (auto& i : v) 24 out << i << std::endl; 25 } 26 27 28 // 把vector<Contestant>对象中的元素写到filename文件中 29 void save(const std::string& filename, std::vector<Contestant>& v) { 30 using std::ofstream; 31 32 ofstream out(filename); 33 if (!out.is_open()) { 34 std::cout << "fail to open file to write\n"; 35 return; 36 } 37 38 output(out, v); 39 out.close(); 40 } 41 42 // 从文件filename读取参赛选手信息到vector<Contestant>对象 43 void load(const std::string& filename, std::vector<Contestant>& v) { 44 using std::ifstream; 45 46 ifstream in(filename); 47 if (!in.is_open()) { 48 std::cout << "fail to open file to read\n"; 49 return; 50 } 51 52 std::string title_line; 53 getline(in, title_line); // 跳过标题行 54 55 int first_column; 56 Contestant t; 57 while (in >> first_column >> t) 58 v.push_back(t); 59 60 in.close(); 61 }
实验任务三
1 #pragma once 2 #include <iostream> 3 #include <stdexcept> 4 #include <cmath> 5 6 using namespace std; 7 8 class Triangle { 9 public: 10 Triangle(double s1, double s2, double s3); 11 ~Triangle() = default; 12 13 double area() const; 14 15 private: 16 double a, b, c; 17 }; 18 19 Triangle::Triangle(double s1, double s2, double s3) : a{ s1 }, b{ s2 }, c{ s3 } { 20 if (a <= 0 || b <= 0 || c <= 0) 21 throw invalid_argument("边长出现负值"); 22 23 if (a + b <= c || b + c <= a || a + c <= b) 24 throw invalid_argument("不满足任意两边之和大于第三边"); 25 } 26 27 double Triangle::area() const { 28 double s = (a + b + c) / 2; 29 return sqrt(s * (s - a) * (s - b) * (s - c)); 30 }
1 #include "Triangle.hpp" 2 #include <iostream> 3 #include <fstream> 4 5 void test() { 6 using namespace std; 7 8 cout << "从文件读入三角形三边边长,计算面积" << endl; 9 10 ifstream in("data3.txt"); 11 if (!in.is_open()) { 12 cout << "fail to open file to read\n"; 13 return; 14 } 15 16 double a, b, c; 17 do { 18 cout << "三角形边长: "; 19 in >> a >> b >> c; 20 cout << a << " " << b << " " << c << endl; 21 22 try { 23 Triangle t(a, b, c); 24 cout << "三角形面积: " << t.area() << endl << endl; 25 } 26 catch (const exception& e) { 27 cout << "error: " << e.what() << endl << endl; 28 } 29 30 if (in.peek() == EOF) 31 break; 32 } while (1); 33 34 in.close(); 35 } 36 37 int main() { 38 test(); 39 }
实验任务四
Vector.hpp
1 #pragma once 2 3 #include<iostream> 4 #include<stdexcept> 5 #include <type_traits> 6 7 using namespace std; 8 9 template<typename T> 10 class Vector { 11 private: 12 int size;//元素数量 13 T* base;//基址 14 public: 15 static T Value() { 16 if constexpr (is_same<T, int>::value) 17 return 0; 18 if constexpr (is_same<T, float>::value) 19 return float(0); 20 if constexpr (is_same<T, double>::value) 21 return double(0); 22 if constexpr (is_same<T, char>::value) 23 return '\0'; 24 } 25 Vector(int a,T b = Value()) { 26 if (a < 0) 27 throw length_error("negetive size!!!"); 28 size = a; 29 base = new T[size]; 30 for (int i = 0; i < size; i++) 31 *(base + i) = b; 32 } 33 Vector(Vector& v) { 34 size = v.size; 35 base = new T[size]; 36 for (int i = 0; i < size; i++) 37 *(base + i) = *(v.base + i); 38 } 39 int get_size() const { 40 return size; 41 } 42 T& at(int a){ 43 if (a > size) 44 throw out_of_range("index out of range!!!"); 45 return *(base+a-1); 46 } 47 T& operator[](int a) { 48 if (a > size) 49 throw out_of_range("index out of range!!!"); 50 return *(base + a - 1); 51 } 52 template<typename T> 53 friend void output(const Vector<T>& v) ; 54 55 }; 56 57 template<typename T> 58 void output(const Vector<T>& v) { 59 for (int i = 0; i < v.size; i++) 60 cout << *(v.base + i) << " "; 61 cout << endl; 62 }
1 #include <iostream> 2 #include "Vector.hpp" 3 4 void test1() { 5 using namespace std; 6 7 int n; 8 cout << "Enter n: "; 9 cin >> n; 10 11 Vector<double> x1(n); 12 for (auto i = 0; i < n; ++i) 13 x1.at(i) = i * 0.7; 14 15 cout << "x1: "; output(x1); 16 17 Vector<int> x2(n, 42); 18 const Vector<int> x3(x2); 19 20 cout << "x2: "; output(x2); 21 cout << "x3: "; output(x3); 22 23 x2.at(0) = 77; 24 x2.at(1) = 777; 25 cout << "x2: "; output(x2); 26 cout << "x3: "; output(x3); 27 } 28 29 void test2() { 30 using namespace std; 31 32 int n, index; 33 while (cout << "Enter n and index: ", cin >> n >> index) { 34 try { 35 Vector<int> v(n, n); 36 v.at(index) = -999; 37 cout << "v: "; output(v); 38 } 39 catch (const exception& e) { 40 cout << e.what() << endl; 41 } 42 } 43 } 44 45 int main() { 46 std::cout << "测试1: 模板类接口测试\n"; 47 test1(); 48 49 std::cout << "\n测试2: 模板类异常处理测试\n"; 50 test2(); 51 }
实验任务五
FileSort.hpp
1 #pragma once 2 3 #include<iostream> 4 #include<string> 5 #include<fstream> 6 #include<iomanip> 7 using namespace std; 8 9 class inf { 10 private: 11 int number; 12 string name; 13 string major; 14 int score; 15 friend bool compare(inf& a, inf& b);//a在前则返回ture 16 friend istream& operator>>(istream& fin, inf& a); 17 friend ostream& operator<<(ostream& fout, inf& a); 18 }; 19 20 bool compare(inf& a, inf& b){ 21 if (a.major > b.major) 22 return 0; 23 else if (a.major < b.major) 24 return 1; 25 else { 26 if (a.score > b.score) 27 return 1; 28 else if (a.score < b.score) 29 return 0; 30 else { 31 if (a.number > b.number) 32 return 1; 33 else 34 return 0; 35 } 36 } 37 } 38 39 istream& operator>>(istream& fin, inf& a) { 40 fin >> a.number >> a.name >> a.major >> a.score; 41 return fin; 42 } 43 44 ostream& operator<<(ostream& fout, inf& a) { 45 fout << left 46 << setw(15) << a.number 47 << setw(15) << a.name 48 << setw(15) << a.major 49 << setw(15) << a.score << endl; 50 return fout; 51 }
FileSort.cpp
1 #include<iostream> 2 #include<string> 3 #include<fstream> 4 #include<iomanip> 5 #include<vector> 6 #include"Filesort.hpp" 7 using namespace std; 8 9 void sort(inf& a, inf& b, bool (*compare)(inf& , inf& )) { 10 if (!compare(a, b)) { 11 inf tmp = a; 12 a = b; 13 b = tmp; 14 } 15 } 16 int main(){ 17 ifstream fin; 18 fin.open("data5.txt"); 19 if (!fin.is_open()) 20 cout << "Failed to open the file!" << endl; 21 vector<inf> inf_list; 22 string firstline;//跳过首行 23 getline(fin, firstline); 24 inf tmp;//临时记录 25 while (fin >> tmp) 26 inf_list.push_back(tmp); 27 fin.close(); 28 bool (*t)(inf&, inf&); 29 t = compare; 30 for (int i = 0; i < inf_list.size() - 1; i++) 31 for (int j = 0; j < inf_list.size() - 1 - i; j++) 32 sort(inf_list[j], inf_list[j + 1], t); 33 //输出到屏幕 34 for (inf i : inf_list) 35 cout << i ; 36 //输出到文件 37 ofstream fout; 38 fout.open("ans5.txt"); 39 if (!fout.is_open()) 40 cout << "Failed to open the file!" << endl; 41 fout << left 42 << setw(15) << "Number" 43 << setw(15) << "Name" 44 << setw(15) << "Major" 45 << setw(15) << "Score" << endl; 46 for (inf i : inf_list) 47 fout << i; 48 fout.close(); 49 return 0; 50 }