实验6 模板类、文件I/O和异常处理
1. 实验任务1
验证性实验
知识点:
- 创建文件并输出内容:
ofstream out("ans.txt"); //ofstream允许程序将数据写入文件; //out("ans.txt")创建一个名为ans.txt的文件,并将这个文件与名为out的ofstream对象关联起来 out << "Hello, world!" << std::endl;//在文件中写入Hello, world! out << a << std::endl;//在文件中写入变量a out.close();//调用close()方法关闭文件流
2. 实验任务2
验证性实验
知识点:
- 从文件中读取:
ifstream in(filename); getline(in, title_line); // 跳过标题行 int first_column; Contestant t; //类 while(in >> first_column >> t) //之前重载了>> v.push_back(t);
- 保存数据到文件:
// 把vector<Constestant>对象中的元素插入到输出流out void output(std::ostream &out, const std::vector<Contestant> &v) { for(auto &i: v) out << i << std::endl; } // 把vector<Contestant>对象中的元素写到filename文件中 void save(const std::string &filename, std::vector<Contestant> &v) { using std::ofstream; ofstream out(filename); output(out, v); out.close(); }
3. 实验任务3
验证性实验
知识点:
try
与catch
try { Triangle t(a, b, c);//尝试创建一个名为t的Triangle类的对象,并传入参数 cout << "三角形面积: " << t.area() << endl << endl;//如果成功创建了三角形对象t }catch(const exception &e) {//catch块用于捕获所有类型的标准异常,当try块中的代码抛出异常时,这个catch块会被执行 cout << "error: " << e.what() << endl << endl; } //在Triangle类的初始化函数中有: if(a <= 0 || b <= 0 || c <= 0) throw invalid_argument("边长出现负值");//抛出异常 if(a+b <= c || b+c <= a || a+c <= b) throw invalid_argument("不满足任意两边之和大于第三边");
peek()
函数:peek()
函数用于查看输入流中的下一个字符,但并不实际提取它。如果没有更多字符可供读取,peek()
将返回特殊值EOF
。if(in.peek() == EOF) break;
4. 实验任务4
Vector.hpp源代码:
#include<iostream>
#include <stdexcept>
#include <vector>
template <typename T>
class Vector {
private:
T* elements;
int capacity;
public:
Vector(int size = 0) : capacity(size) {
if (size < 0) {
throw std::length_error("negative size");
}
elements = new T[size];
}
Vector(int size, T value) : capacity(size) {
if (size < 0) {
throw std::length_error("negative size");
}
elements = new T[size];
for (int i = 0; i < size; ++i) {
elements[i] = value;
}
}
Vector(const Vector<T>& other) : capacity(other.capacity) {
elements = new T[capacity];
for (int i = 0; i < capacity; ++i) {
elements[i] = other.elements[i];
}
}
~Vector() {
delete[] elements;
}
//其它成员函数
int get_size() const {
return capacity;
}
T& at(int index) {//返回值类型是T&,即对模板类型T的引用,意味着函数返回的是对存储在Vector中的元素的引用
if (index >= capacity) {
throw std::out_of_range("index out of range");
}
return elements[index];
}
T& operator[](int index) {
return at(index);
}
template <typename T>
friend void output(const Vector<T>& V);
};
template <typename T>
void output(const Vector<T>& V) {//Vector<T> 类型对象的常量引用
for (int i = 0; i < V.capacity; ++i) {
std::cout << V.elements[i] << " ";
}
std::cout << std::endl;
}
task4.cpp源代码:
#include <iostream>
#include "Vector.hpp"
void test1() {
using namespace std;
int n;
cout << "Enter n: ";
cin >> n;
Vector<double> x1(n);
for(auto i = 0; i < n; ++i)
x1.at(i) = i * 0.7;
cout << "x1: "; output(x1);
Vector<int> x2(n, 42);
const Vector<int> x3(x2);
cout << "x2: "; output(x2);
cout << "x3: "; output(x3);
x2.at(0) = 77;
x2.at(1) = 777;
cout << "x2: "; output(x2);
cout << "x3: "; output(x3);
}
void test2() {
using namespace std;
int n, index;
while(cout << "Enter n and index: ", cin >> n >> index) {
try {
Vector<int> v(n, n);
v.at(index) = -999;
cout << "v: "; output(v);
}
catch (const exception &e) {
cout << e.what() << endl;
}
}
}
int main() {
std::cout << "测试1: 模板类接口测试\n";
test1();
std::cout << "\n测试2: 模板类异常处理测试\n";
test2();
}
运行截图:
5. 实验任务5
task5.cpp源代码:
#include <iostream>
#include <vector>
#include <string>
#include <iomanip>
#include <string>
#include <fstream>
#include <algorithm>
class Student {
public:
std::string no; //学号
std::string name; //姓名
std::string major; //专业
int score; //分数
//重载流插入运算符<<
friend std::ostream& operator<<(std::ostream& out, const Student& s);
//重载流提取运算符>>
friend std::istream& operator>>(std::istream& in, Student& s);
};
std::ostream& operator<<(std::ostream& out, const Student& s) {
out << std::left;
out << std::setw(15) << s.no
<< std::setw(15) << s.name
<< std::setw(15) << s.major
<< std::setw(5) << s.score;
return out;
}
std::istream& operator>>(std::istream& in, Student& s) {
in >> s.no >> s.name >> s.major >> s.score;
return in;
}
//比较函数,用于排序
bool compareStudents(const Student& a, const Student& b) {
if (a.major < b.major) return true;
else if (a.major == b.major && a.score > b.score) return true;
return false;
}
int main() {
std::vector<Student> students;
// 从data5.txt读取数据
std::ifstream inFile("data5.txt");
if (!inFile.is_open()) {
std::cout << "fail to open file to write\n";
return 0;
}
if (inFile) {
std::string title_line;
std::getline(inFile, title_line); // 跳过标题行
Student s;
while (inFile >> s)
students.push_back(s);
inFile.close();
}
// 排序
std::sort(students.begin(), students.end(), compareStudents);
// 输出到屏幕并保存到ans5.txt
std::ofstream outFile("ans5.txt");
if (outFile) {
for (auto& i : students) {
std::cout << i << std::endl;
outFile << i << std::endl;
}
outFile.close();
}
return 0;
}
运行截图:
实验总结:
本次实验综合运用到了try
与catch
函数、peek()
函数、模板类、文件的输入与输出等,实验4中的模板类令我印象深刻:T& at(int index);
该函数返回值类型是T&,即对模板类型T的引用,意味着函数返回的是对存储在Vector中的元素的引用,这是第一次遇到这样的类型。实验5综合运用了各种知识,包括运算符重载、文件输入输出等,特别是对c++库中的sort函数的应用,实现了对与多项项目的排序,很有意义。