一 实验目的
- 练习编写模板函数、模板类,从多态角度理解模板函数和模板类(类型作为参数)
- 体验标准I/O流类、文件I/O流类、字符串I/O流类的用法,能正确使用
- 针对问题场景,使用流类库对I/O数据进行格式化和读、写操作
- 体验异常处理的基础用法,能解释异常处理的机制和流程
- 训练综合应用类的封装、继承、多态特性及现代C++标准库编写正确、高效、安全代码
二 实验步骤
task1
complex.hpp
#pragma once
#include <iostream>
#include <stdexcept>
// 声明
////////////////////////////////////////////////////
// 复数模板类声明
template<typename T>
class Complex {
public:
Complex(T r = 0, T i = 0);
Complex(const Complex<T> &c);
T get_real() const;
T get_imag() const;
// 重载+=为成员函数
Complex<T>& operator+=(const Complex<T> &c);
// 重载<<、>>为友元函数
template<typename T1>
friend std::ostream& operator<<(std::ostream &out, const Complex<T1> &c);
template<typename T1>
friend std::istream& operator>>(std::istream &in, Complex<T1> &c);
private:
T real, imag;
};
// 普通函数声明
// 重载+用于Complex类型
template<typename T>
Complex<T> operator+(const Complex<T> &c1, const Complex<T> &c2);
// 重载==用于Complex类型
template<typename T>
bool operator==(const Complex<T> &c1, const Complex<T> &c2);
// 实现
////////////////////////////////////////////////////
// 成员函数模板实现
template<typename T>
Complex<T>::Complex(T r, T i): real{r}, imag{i} {
}
template<typename T>
Complex<T>::Complex(const Complex<T> &c): real{c.real}, imag{c.imag} {
}
template<typename T>
T Complex<T>::get_real() const {
return real;
}
template<typename T>
T Complex<T>::get_imag() const {
return imag;
}
// 重载+=为成员函数
template<typename T>
Complex<T>& Complex<T>::operator+=(const Complex<T> &c) {
real += c.real;
imag += c.imag;
return *this;
}
///////////////////////////////////////
// 友元函数模板实现
template<typename T1>
std::ostream& operator<<(std::ostream &out, const Complex<T1> &c) {
if(c.imag >= 0)
out << c.real << " + " << c.imag << "i";
else
out << c.real << " - " << -c.imag << "i";
return out;
}
template<typename T1>
std::istream& operator>>(std::istream &in, Complex<T1> &c) {
in >> c.real >> c.imag;
return in;
}
///////////////////////////////////////
// 普通函数模板实现
// 重载+用于Complex类型
template<typename T>
Complex<T> operator+(const Complex<T> &c1, const Complex<T> &c2) {
return Complex<T>(c1.get_real()+c2.get_real(),
c1.get_imag()+c2.get_imag());
}
// 重载==用于Complex类型
template<typename T>
bool operator==(const Complex<T> &c1, const Complex<T> &c2) {
return c1.get_real() == c2.get_real() &&
c1.get_imag() && c2.get_imag();
}
task1.cpp
#include "Complex.hpp"
#include <iostream>
#include <fstream>
#include <stdexcept>
void test1();
void test2();
int main() {
using namespace std;
cout << "测试1: 复数模板类测试" << endl;
test1();
cout << "\n测试2: 文件I/O测试" << endl;
test2();
}
void test1() {
using namespace std;
Complex<double> c1{3.5, 2}, c2;
cout << "Enter c2: ";
cin >> c2;
cout << "c1 = " << c1 << endl;
cout << "c2 = " << c2 << endl;
cout << "c1 == c2: " << boolalpha << (c1 == c2) << endl;
cout << "c1 + c2 = " << c1 + c2 << endl;
c1 += c2;
cout << "c1.real = " << c1.get_real() << endl;
cout << "c1.imag = " << c1.get_imag() << endl;
cout << "c1 == c2: " << boolalpha << (c1 == c2) << endl;
}
void test2() {
using namespace std;
Complex<int> c1{1, 2}, c2{9, -7};
ofstream out("ans.txt");
if(!out.is_open()) {
cout << "fail to open file ans.txt to write\n";
return;
}
out << "c1 = " << c1 << endl;
out << "c2 = " << c2 << endl;
out << "c1 + c2 = " << c1 + c2 << endl;
out << "(c1 == c2) = " << boolalpha << (c1 == c2) << endl;
out.close();
cout << "测试ok!" << endl;
}
task2
contestant.hpp
#pragma once
#include <iostream>
#include <iomanip>
#include <string>
using std::string;
using std::ostream;
using std::istream;
using std::setw;
using std::setprecision;
using std::setiosflags;
using std::ios_base;
// Contestant类声明
class Contestant {
public:
Contestant() = default;
~Contestant() = default;
int get_num() const { return num; }
float get_time_usage() const { return time_usage; }
friend ostream& operator<<(ostream &out, const Contestant &c);
friend istream& operator>>(istream &in, Contestant &c);
private:
string no; // 学号
string name; // 姓名
string major; // 专业
int num; // 解题数
float time_usage; // 总用时
};
// 友元函数实现
// 重载流插入运算符<<
ostream& operator<<(ostream &out, const Contestant &c) {
out << setiosflags(ios_base::left);
out << setw(15) << c.no
<< setw(15) << c.name
<< setw(15) << c.major
<< setw(5) << c.num
<< setprecision(2) << c.time_usage;
return out;
}
// 重载流提取运算符>>
istream& operator>>(istream &in, Contestant &c) {
in >> c.no >> c.name >> c.major >> c.num >> c.time_usage;
return in;
}
utils.hpp
#include "Contestant.hpp"
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
// 排序函数
// 按解题数比较,解题数相同的情况下,按总用时比较,总用时越少,排名越靠前
bool compare_by_solutionInfo(const Contestant &c1, const Contestant &c2) {
if(c1.get_num() > c2.get_num())
return true;
if(c1.get_num() == c2.get_num())
return c1.get_time_usage() < c2.get_time_usage();
return false;
}
// 把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);
if(!out.is_open()) {
std::cout << "fail to open file to write\n";
return;
}
output(out, v);
out.close();
}
// 从文件filename读取参赛选手信息到vector<Contestant>对象
void load(const std::string &filename, std::vector<Contestant> &v) {
using std::ifstream;
ifstream in(filename);
if(!in.is_open()) {
std::cout << "fail to open file to read\n";
return;
}
std::string title_line;
getline(in, title_line); // 跳过标题行
int first_column;
Contestant t;
while(in >> first_column >> t)
v.push_back(t);
in.close();
}
task2.cpp
#include "Contestant.hpp"
#include "utils.hpp"
#include <iostream>
#include <vector>
#include <algorithm>
void test() {
using namespace std;
vector<Contestant> v;
load("data2.txt", v); // 从文件加载选手信息到对象v
sort(v.begin(), v.end(), compare_by_solutionInfo); // 按解题情况排序
output(cout, v); // 输出对象v中信息到屏幕
save("ans.txt", v); // 把对象v中选手信息保存到文件
}
int main() {
test();
}
task3
traingle.hpp
#include <iostream>
#include <stdexcept>
#include <cmath>
using namespace std;
class Triangle {
public:
Triangle(double s1, double s2, double s3);
~Triangle() = default;
double area() const;
private:
double a, b, c;
};
Triangle::Triangle(double s1, double s2, double s3): a{s1}, b{s2}, c{s3} {
if(a <= 0 || b <= 0 || c <= 0)
throw invalid_argument("边长出现负值");
if(a+b <= c || b+c <= a || a+c <= b)
throw invalid_argument("不满足任意两边之和大于第三边");
}
double Triangle::area() const {
double s = (a + b + c)/2;
return sqrt(s*(s-a)*(s-b)*(s-c));
}
task3.cpp
#include "Triangle.hpp"
#include <iostream>
#include <fstream>
void test() {
using namespace std;
cout << "从文件读入三角形三边边长,计算面积" << endl;
ifstream in("data3.txt");
if(!in.is_open()) {
cout << "fail to open file to read\n";
return;
}
double a,b,c;
do {
cout << "三角形边长: ";
in >> a >> b >> c;
cout << a << " " << b << " " << c << endl;
try {
Triangle t(a, b, c);
cout << "三角形面积: " << t.area() << endl << endl;
}catch(const exception &e) {
cout << "error: " << e.what() << endl << endl;
}
if(in.peek() == EOF)
break;
} while(1);
in.close();
}
int main() {
test();
}
task4
vector.hpp
#pragma once
#include<iostream>
#include<stdexcept>
using namespace std;
template<typename T>
class Vector
{
private:
int size;
T* ptr;
public:
Vector(int n);
Vector(int n, T value);
Vector(const Vector<T>& v);
~Vector();
int get_size()
{
return size;
}
T& at(int index)const;
T& at(int index);
T& operator[](int index)const;
T& operator[](int index);
template<typename T1>
friend void output(const Vector<T1>& v);
};
template<typename T>
Vector<T>::Vector(int n) :size(n)
{
if (n < 0)
{
throw length_error("Vector constructor:negative size");
}
else
{
ptr = new T[size];
}
}
template<typename T>
Vector<T>::Vector(int n,T value):size(n)
{
if (n < 0)
{
throw length_error("Vector constructor:negative size");
}
else
{
ptr = new T[size];
for (int i = 0; i < size; i++)
{
ptr[i] = value;
}
}
}
template<typename T>
Vector<T>::Vector(const Vector<T>& v):size(v.size),ptr(new T[size])
{
for (int i = 0; i < size; i++)
{
ptr[i] = v.ptr[i];
}
}
template<typename T>
Vector<T>::~Vector()
{
delete[]ptr;
}
template<typename T>
T& Vector<T>::at(int index)const
{
if (index < 0 || index >= size)
{
throw out_of_range("Vector:index out of range");
}
else
{
return ptr[index];
}
}
template<typename T>
T& Vector<T>::at(int index)
{
return static_cast<const Vector*>(this)->at(index);
}
template<typename T>
T& Vector<T>::operator[](int index)const
{
if (index < 0 || index >= size)
{
throw out_of_range("Vector:index out of range");
}
else
{
return ptr[index];
}
}
template<typename T>
T& Vector<T>::operator[](int index)
{
return static_cast<const Vector*>(this)->operator[](index);
}
template<typename T>
void output(const Vector<T>& v)
{
for (int i = 0; i < v.size; i++)
{
cout << v.ptr[i] << ", ";
}
cout <<"\b\b " << endl;
}
task4.cpp
#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() {
cout << "测试1: 模板类接口测试\n";
test1();
cout << "\n测试2: 模板类异常处理测试\n";
test2();
}
task5
people.hpp
#pragma once
#include<iostream>
#include<string>
#include<iomanip>
using namespace std;
class people
{
private:
int xuehao;
string name;
string major;
int score;
public:
people() = default;
~people() = default;
string get_major()const
{
return major;
}
int get_score()const
{
return score;
}
friend ostream& operator<<(ostream& out, people& p);
friend istream& operator>>(istream& in, people& p);
};
ostream& operator<<(ostream& out, people& p)
{
out << setiosflags(ios_base::left);
out << setw(10) << p.xuehao
<< setw(10) << p.name
<< setw(10) << p.major
<< setw(10) << p.score << endl;
return out;
}
istream& operator>>(istream& in, people& p)
{
in >> p.xuehao >> p.name >> p.major >> p.score;
return in;
}
tools.hpp
#pragma once
#include"people.hpp"
#include<iostream>
#include<string>
#include<fstream>
#include<vector>
bool paixu(const people& p1, const people& p2)
{
if (p1.get_major() < p2.get_major())
{
return true;
}
if (p1.get_major() == p2.get_major())
{
return p1.get_score() > p2.get_score();
}
return false;
}
void output(ostream& out, vector<people>& v)
{
for (auto& i : v)
{
out << i;
}
}
void save(const string& filename, vector<people>& v)
{
ofstream out(filename);
if (!out.is_open())
{
cout << "文件写入失败" << endl;
exit(0);
}
output(out, v);
out.close();
}
void load(const string& filename, vector<people>& v)
{
ifstream in(filename);
if (!in.is_open())
{
cout << "文件读出失败" << endl;
exit(0);
}
string firstline;
getline(in, firstline);
people p;
while (in >> p)
{
v.push_back(p);
}
in.close();
}
task5.cpp
#include"people.hpp"
#include"tools.hpp"
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
int main()
{
vector<people> v;
load("data5.txt", v);
sort(v.begin(), v.end(), paixu);
output(cout, v);
save("ans.txt", v);
return 0;
}
```![](/i/l/?n=24&i=blog/3533458/202412/3533458-20241224103652016-1547751231.png)
标签:std,文件,const,Vector,get,Complex,实验,include,模板
From: https://www.cnblogs.com/fantasies31/p/18626847