实验4
实验任务2:
GradeCalc.hpp:
1 #include<iostream> 2 #include<vector> 3 #include<string> 4 #include<algorithm> 5 #include<numeric> 6 #include<iomanip> 7 8 using std::vector; 9 using std::string; 10 using std::cin; 11 using std::cout; 12 using std::endl; 13 14 class GradeCalc:public vector<int>{ 15 public: 16 GradeCalc(const string &cname,int size); 17 void input(); 18 void output() const; 19 void sort(bool ascending = false); 20 int min() const; 21 int max() const; 22 float average() const; 23 void info(); 24 25 private: 26 void compute(); 27 28 private: 29 string course_name; 30 int n; 31 vector<int> counts = vector<int>(5,0); 32 vector<double> rates = vector<double>(5,0); 33 }; 34 35 GradeCalc::GradeCalc(const string &cname,int size):course_name{cname},n{size}{} 36 37 void GradeCalc::input(){ 38 int grade; 39 40 for(int i = 0;i<n;++i){ 41 cin >> grade; 42 this->push_back(grade); 43 } 44 } 45 46 void GradeCalc::output() const { 47 for(auto ptr = this->begin();ptr!=this->end();++ptr) 48 cout << *ptr << " "; 49 cout << endl; 50 } 51 52 void GradeCalc::sort(bool ascending){ 53 if(ascending) 54 std::sort(this->begin(),this->end()); 55 else 56 std::sort(this->begin(),this->end(),std::greater<int>()); 57 } 58 59 int GradeCalc::min() const { 60 return *std::min_element(this->begin(),this->end()); 61 } 62 63 int GradeCalc::max() const { 64 return *std::max_element(this->begin(),this->end()); 65 } 66 67 float GradeCalc::average() const { 68 return std::accumulate(this->begin(),this->end(),0)*1.0/n; 69 } 70 71 void GradeCalc::compute(){ 72 for(int grade:*this){ 73 if(grade<60) 74 counts.at(0)++; 75 else if(grade >= 60 && grade < 70) 76 counts.at(1)++; 77 else if(grade >= 70 && grade < 80) 78 counts.at(2)++; 79 else if(grade >= 80 && grade < 90) 80 counts.at(3)++; 81 else if(grade >= 90) 82 counts.at(4)++; 83 } 84 85 for(int i = 0;i<rates.size();++i) 86 rates.at(i) = counts.at(i)*1.0/n; 87 } 88 89 void GradeCalc::info(){ 90 cout << "课程名称:\t" << course_name << endl; 91 cout << "排序后成绩:\t"; 92 sort(); 93 output(); 94 cout << "最高分:\t" << max() << endl; 95 cout << "最低分:\t" << min() << endl; 96 cout << "平均分:\t" << std::fixed << std::setprecision(2) << average() << endl; 97 98 compute(); 99 100 vector<string> tmp{"[0,60) ","[60,70) ","[70,80) ","[80,90) ","[90,100] "}; 101 for(int i = tmp.size()-1;i>=0;--i) 102 cout << tmp[i] << "\t: " << counts[i] << "人\t " << std::fixed << std::setprecision(2) << rates[i]*100 << "%" << endl; 103 }
task2.cpp:
1 #include"GradeCalc.hpp" 2 #include<iomanip> 3 4 void test(){ 5 int n; 6 cout << "输入班级人数: "; 7 cin >> n; 8 9 GradeCalc c1("OOP",n); 10 11 cout << "录入成绩: " << endl; 12 c1.input(); 13 cout << "输出成绩: " << endl; 14 c1.output(); 15 16 cout << string(20,'*') + "课程成绩信息" + string(20,'*') << endl; 17 c1.info(); 18 } 19 20 int main(){ 21 test(); 22 }
问题1:成绩储存在vector<int>中;都是通过this指针访问到每个成绩;input通过cin读取并通过push_back存入。
问题2:求平均分;有影响;将整数转换成浮点数。
问题3:可以增加对浮点数成绩的支持,让GradeCalc功能更完善。
实验任务3:
GradeCalc.hpp:
1 #include<iostream> 2 #include<vector> 3 #include<string> 4 #include<algorithm> 5 #include<numeric> 6 #include<iomanip> 7 8 using std::vector; 9 using std::string; 10 using std::cin; 11 using std::cout; 12 using std::endl; 13 14 class GradeCalc{ 15 public: 16 GradeCalc(const string &cname,int size); 17 void input(); 18 void output() const; 19 void sort(bool ascending = false); 20 int min() const; 21 int max() const; 22 float average() const; 23 void info(); 24 25 private: 26 void compute(); 27 28 private: 29 string course_name; 30 int n; 31 vector<int> grades; 32 vector<int> counts = vector<int>(5,0); 33 vector<double> rates = vector<double>(5,0); 34 }; 35 36 GradeCalc::GradeCalc(const string &cname,int size):course_name{cname},n{size}{} 37 38 void GradeCalc::input(){ 39 int grade; 40 41 for(int i = 0;i<n;++i){ 42 cin >> grade; 43 grades.push_back(grade); 44 } 45 } 46 47 void GradeCalc::output() const { 48 for(int grade:grades) 49 cout << grade << " "; 50 cout << endl; 51 } 52 53 void GradeCalc::sort(bool ascending){ 54 if(ascending) 55 std::sort(grades.begin(),grades.end()); 56 else 57 std::sort(grades.begin(),grades.end(),std::greater<int>()); 58 } 59 60 int GradeCalc::min() const { 61 return *std::min_element(grades.begin(),grades.end()); 62 } 63 64 int GradeCalc::max() const { 65 return *std::max_element(grades.begin(),grades.end()); 66 } 67 68 float GradeCalc::average() const { 69 return std::accumulate(grades.begin(),grades.end(),0)*1.0/n; 70 } 71 72 void GradeCalc::compute(){ 73 for(int grade:grades){ 74 if(grade<60) 75 counts.at(0)++; 76 else if(grade >= 60 && grade < 70) 77 counts.at(1)++; 78 else if(grade >= 70 && grade < 80) 79 counts.at(2)++; 80 else if(grade >= 80 && grade < 90) 81 counts.at(3)++; 82 else if(grade >= 90) 83 counts.at(4)++; 84 } 85 86 for(int i = 0;i<rates.size();++i) 87 rates.at(i) = counts.at(i)*1.0/n; 88 } 89 90 void GradeCalc::info(){ 91 cout << "课程名称:\t" << course_name << endl; 92 cout << "排序后成绩:\t"; 93 sort(); 94 output(); 95 cout << "最高分:\t" << max() << endl; 96 cout << "最低分:\t" << min() << endl; 97 cout << "平均分:\t" << std::fixed << std::setprecision(2) << average() << endl; 98 99 compute(); 100 101 vector<string> tmp{"[0,60) ","[60,70) ","[70,80) ","[80,90) ","[90,100] "}; 102 for(int i = tmp.size()-1;i>=0;--i) 103 cout << tmp[i] << "\t: " << counts[i] << "人\t " << std::fixed << std::setprecision(2) << rates[i]*100 << "%" << endl; 104 }
task3.cpp:
1 #include"GradeCalc.hpp" 2 #include<iomanip> 3 4 void test(){ 5 int n; 6 cout << "输入班级人数: "; 7 cin >> n; 8 9 GradeCalc c1("OOP",n); 10 11 cout << "录入成绩: " << endl; 12 c1.input(); 13 cout << "输出成绩: " << endl; 14 c1.output(); 15 16 cout << string(20,'*') + "课程成绩信息" + string(20,'*') << endl; 17 c1.info(); 18 } 19 20 int main(){ 21 test(); 22 }
问题1:储存在vector<int> grades中;通过grades访问每一个成绩。实验任务2是通过this指针来访问,而实验任务3是通过直接读取和操作grades中的数据来实现功能。
问题2:除了直接读取和操作,我们还可以通过this指针来访问,而这可以更方便的操作对象的成员。
实验任务4:
task4_1.cpp:
1 #include<iostream> 2 #include<string> 3 #include<limits> 4 5 using namespace std; 6 7 void test1(){ 8 string s1,s2; 9 cin >> s1 >> s2; 10 cout << "s1: " << s1 << endl; 11 cout << "s2: " << s2 << endl; 12 } 13 14 void test2(){ 15 string s1,s2; 16 getline(cin,s1); 17 getline(cin,s2); 18 cout << "s1: " << s1 << endl; 19 cout << "s2: " << s2 << endl; 20 } 21 22 void test3(){ 23 string s1,s2; 24 getline(cin,s1,' '); 25 getline(cin,s2); 26 cout << "s1: " << s1 << endl; 27 cout << "s2: " << s2 << endl; 28 } 29 30 int main(){ 31 cout << "测试1:使用标准输入流对象cin输入字符串" << endl; 32 test1(); 33 cout << endl; 34 35 cin.ignore(numeric_limits<streamsize>::max(),'\n'); 36 37 cout << "测试2:使用函数getline()输入字符串" << endl; 38 test2(); 39 cout << endl; 40 41 cout << "测试3:使用函数getline()输入字符串,指定字符串分隔符" << endl; 42 test3(); 43 }
问题1:
主要用途是在控制台输入时,清除输入缓冲区中剩余的输入数据,直到遇到换行符(\n
),或直到达到输入流的最大限制。总的来说,cin.ignore(numeric_limits<streamsize>::max(), '\n');
是一个防护措施,确保输入流的状态一致,避免多余数据干扰后续的输入。这种用法在处理交替的整数和字符串输入时尤其重要。
task4_2.cpp:
1 #include<iostream> 2 #include<string> 3 #include<vector> 4 #include<limits> 5 6 using namespace std; 7 8 void output(const vector<string> &v){ 9 for(auto &s:v) 10 cout << s << endl; 11 } 12 13 void test(){ 14 int n; 15 while(cout << "Enter n: ",cin >> n){ 16 vector<string> v1; 17 18 for(int i = 0;i<n;++i){ 19 string s; 20 cin >>s; 21 v1.push_back(s); 22 } 23 24 cout << "output v1: " << endl; 25 output(v1); 26 cout << endl; 27 } 28 } 29 30 int main(){ 31 cout << "测试:使用cin多组输入字符串" << endl; 32 test(); 33 }
task4_3.cpp:
1 #include<iostream> 2 #include<string> 3 #include<vector> 4 #include<limits> 5 6 using namespace std; 7 8 void output(const vector<string> &v){ 9 for(auto &s:v) 10 cout << s << endl; 11 } 12 13 void test(){ 14 int n; 15 while(cout << "Enter n: ",cin >> n){ 16 cin.ignore(numeric_limits<streamsize>::max(),'\n'); 17 18 vector<string> v2; 19 20 for(int i = 0;i<n;++i){ 21 string s; 22 getline(cin,s); 23 v2.push_back(s); 24 } 25 cout << "output v2: " << endl; 26 output(v2); 27 cout << endl; 28 } 29 } 30 31 int main(){ 32 cout << "测试:使用函数getline()多组输入字符串" << endl; 33 test(); 34 }
问题2:
cin.ignore(numeric_limits<streamsize>::max(), '\n');
这一行代码的主要目的是清除输入流中可能残留的多余字符,尤其是在处理输入时保持输入流的状态良好,以避免对后续输入造成干扰。in.ignore(numeric_limits<streamsize>::max(), '\n')
确保了输入缓冲区被清空,没有多余的换行符或其他字符干扰 getline()
函数的正常运作。这是一个常见且重要的输入处理技巧,在用户交互的程序设计中尤其有用。
实验任务5:
grm.hpp:
1 #include <iostream> 2 #include <string> 3 4 using std::cout; 5 using std::endl; 6 7 template <typename T> 8 class GameResourceManager { 9 public: 10 GameResourceManager(T initial); 11 T get() const; 12 void update(T amount); 13 14 private: 15 T resource; 16 }; 17 18 template<typename T> 19 GameResourceManager<T>::GameResourceManager(T initial) : resource(initial) { 20 } 21 22 template<typename T> 23 GameResourceManager<T>::get() const { 24 return resource; 25 } 26 27 template<typename T> 28 void GameResourceManager<T>::update(T amount) { 29 resource += amount; 30 if (resource < 0) { 31 resource = 0; 32 } 33 }
task5.cpp:
1 #include "grm.hpp" 2 #include <iostream> 3 4 using std::cout; 5 using std::endl; 6 7 void test1() { 8 GameResourceManager<float> HP_manager(99.99); 9 cout << "当前生命值: " << HP_manager.get() << endl; 10 HP_manager.update(9.99); 11 cout << "增加9.99生命值后, 当前生命值: " << HP_manager.get() << endl; 12 HP_manager.update(-999.99); 13 cout << "减少999.99生命值后, 当前生命值: " << HP_manager.get() << endl; 14 } 15 16 void test2() { 17 GameResourceManager<int> Gold_manager(100); 18 cout << "当前金币数量: " << Gold_manager.get() << endl; 19 Gold_manager.update(50); 20 cout << "增加50个金币后, 当前金币数量: " << Gold_manager.get() << endl; 21 Gold_manager.update(-99); 22 cout << "减少99个金币后, 当前金币数量: " << Gold_manager.get() << endl; 23 } 24 25 int main() { 26 cout << "测试1: 用float类型对类模板GameResourceManager实例化" << endl; 27 test1(); 28 cout << endl; 29 30 cout << "测试2: 用int类型对类模板GameResourceManager实例化" << endl; 31 test2(); 32 33 }
实验任务6:
info.hpp:
1 #include <iostream> 2 #include <string> 3 4 using std::cout; 5 using std::endl; 6 using std::string; 7 8 class Info { 9 public: 10 Info(const string &name, const string &contact, const string &city, int n); 11 void display() const; 12 13 private: 14 string name; 15 string contact; 16 string city; 17 int n; 18 }; 19 20 Info::Info(const string &name, const string &contact, const string &city, int n) : name(name), contact(contact), city(city), n(n) {} 22 23 void Info::display() const { 24 cout << "昵称: " << name << endl; 25 cout << "联系方式: " << contact << endl; 26 cout << "所在城市: " << city << endl; 27 cout << "预定人数: " << n << endl; 28 }
task6.cpp:
1 #include "info.hpp" 2 #include <iostream> 3 #include <vector> 4 #include <iomanip> 5 6 using namespace std; 7 8 const int capacity = 100; 9 10 void test(){ 11 vector<Info> audience_lst; 12 int people = 0; 13 cout << "昵称"; 14 cout << setw(30) << "联系方式(邮箱/手机号)"; 15 cout << setw(15) << "所在城市"; 16 cout << setw(15) << "预定参加人数" << endl; 17 string name, contact, city; 18 int n; 19 while (cin >> name >> contact >> city >> n){ 20 if(people >= capacity){ 21 break; 22 } 23 if(people + n > capacity){ 24 cout << "对不起,只剩" << capacity - people << "个位置." << endl; 25 cout << "1.输入u,更新(update)预定信息" << endl; 26 cout << "2.输入q,退出预定" << endl; 27 cout << "你的选择是:"; 28 char option; 29 cin >> option; 30 if(option == 'q'){ 31 break; 32 } 33 else{ 34 cout << "请重新输入预定信息: " << endl; 35 cin >> name >> contact >> city >> n; 36 } 37 } 38 audience_lst.emplace_back(name, contact, city, n); 39 people += n; 40 } 41 cout << endl; 42 cout << "截至目前,一共有" << people << "位听众预约。"; 43 cout << "预约听众信息如下:" << endl; 44 cout << string(40, '-') << endl; 45 for(const auto &i :audience_lst){ 46 i.display(); 47 cout << string(40, '-') << endl; 48 } 49 } 50 51 int main(){ 52 test(); 53 return 0; 54 }
实验任务7:
date.h:
1 #ifndef __DATE_H__ 2 #define __DATE_H__ 3 4 class Date { 5 private: 6 int year; 7 int month; 8 int day; 9 int totalDays; 10 11 public: 12 Date(int year, int month, int day); 13 int getYear() const { return year; } 14 int getMonth() const { return month; } 15 int getDay() const { return day; } 16 int getMaxDay() const; 17 bool isLeapYear() const { 18 return (year % 4 == 0 && year % 100 != 0 || year % 400 == 0); 19 } 20 void show() const; 21 int distance(const Date& date) const { 22 return totalDays - date.totalDays; 23 } 24 }; 25 26 #endif // __DATE_H__
date.cpp:
1 #include "date.h" 2 #include <iostream> 3 #include <cstdlib> 4 using namespace std; 5 6 namespace { 7 const int DAYS_BEFORE_MONTH[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}; 8 } 9 10 Date::Date(int year, int month, int day) : year(year), month(month), day(day) { 11 if (day <= 0 || day > getMaxDay()) { 12 cout << "Invalid date: "; 13 show(); 14 cout << endl; 15 exit(1); 16 } 17 int years = year - 1; 18 totalDays = years * 365 + years / 4 - years / 100 + years / 400 + DAYS_BEFORE_MONTH[month-1] + day; 19 20 if (isLeapYear() && month > 2) { 21 totalDays++; 22 } 23 } 24 25 int Date::getMaxDay() const { 26 if (isLeapYear() && month == 2) { 27 return 29; 28 } 29 else{ 30 return DAYS_BEFORE_MONTH[month]-DAYS_BEFORE_MONTH[month-1]; 31 } 32 } 33 34 void Date::show() const { 35 cout << getYear() << "-" << getMonth() << "-" << getDay(); 36 }
accumulator.h:
1 #ifndef __ACCUMULATOR_H__ 2 #define __ACCUMULATOR_H__ 3 4 #include "date.h" 5 6 class Accumulator { 7 private: 8 Date lastDate; 9 double value; 10 double sum; 11 12 public: 13 Accumulator(const Date &date, double value) : lastDate(date), value(value), sum(0) {} 14 15 double getSum(const Date &date) const { 16 return sum + (date.distance(lastDate) * value); 17 } 18 19 void change(const Date &date, double value) { 20 sum = getSum(date); 21 lastDate = date; 22 this->value = value; 23 } 24 25 void reset(const Date &date, double value) { 26 lastDate = date; 27 this->value = value; 28 sum = 0; 29 } 30 }; 31 #endif // __ACCUMULATOR_H__
account.h:
1 #ifndef __ACCOUNT_H__ 2 #define __ACCOUNT_H__ 3 4 #include "date.h" 5 #include "accumulator.h" 6 #include <string> 7 8 class Account { 9 private: 10 std::string id; 11 double balance; 12 static double total; 13 14 protected: 15 Account(const Date &date, const std::string &id); 16 void record(const Date &date, double amount, const std::string &desc); 17 void error(const std::string &msg) const; 18 19 public: 20 const std::string &getId() const { return id; } 21 double getBalance() const { return balance; } 22 static double getTotal() { return total; } 23 void show() const; 24 }; 25 26 class SavingsAccount : public Account { 27 private: 28 Accumulator acc; 29 double rate; 30 31 public: 32 SavingsAccount(const Date &date, const std::string &id, double rate); 33 double getRate() const { return rate; } 34 void deposit(const Date &date, double amount, const std::string &desc); 35 void withdraw(const Date &date, double amount, const std::string &desc); 36 void settle(const Date &date); 37 }; 38 39 class CreditAccount : public Account { 40 private: 41 Accumulator acc; 42 double credit; 43 double rate; 44 double fee; 45 double getDebt() const { 46 double balance = getBalance(); 47 return (balance < 0 ? balance : 0); 48 } 49 50 public: 51 CreditAccount(const Date &date, const std::string &id, double credit, double rate, double fee); 52 double getCredit() const { return credit; } 53 double getRate() const { return rate; } 54 double getFee() const { return fee; } 55 double getAvailableCredit() const { 56 if (getBalance() < 0) 57 return credit + getBalance(); 58 else 59 return credit; 60 } 61 void deposit(const Date &date, double amount, const std::string &desc); 62 void withdraw(const Date &date, double amount, const std::string &desc); 63 void settle(const Date &date); 64 void show() const; 65 };; 66 67 #endif // __ACCOUNT_H__
account,cpp:
1 #include"account.h" 2 #include<cmath> 3 #include<iostream> 4 using namespace std; 5 double Account::total = 0; 6 7 Account::Account(const Date& date, const string& id) :id{ id }, balance{ 0 } { 8 date.show(); cout << "\t#" << id << "created" << endl; 9 } 10 11 12 void Account::record(const Date& date, double amount, const string& desc) { 13 amount = floor(amount * 100 + 0.5) / 100; 14 balance += amount; 15 total += amount; 16 date.show(); 17 cout << "\t#" << id << "\t" << amount << "\t" << balance << "\t" << desc << endl; 18 } 19 20 void Account::show()const { cout << id << "\tBalance:" << balance; } 21 void Account::error(const string& msg)const { 22 cout << "Error(#" << id << "):" << msg << endl; 23 } 24 25 SavingsAccount::SavingsAccount(const Date&date,const string&id,double rate):Account(date,id),rate(rate), acc(date,0){} 26 27 void SavingsAccount::deposit(const Date& date, double amount, const string& desc) { 28 record(date, amount, desc); 29 acc.change(date, getBalance()); 30 } 31 32 void SavingsAccount::withdraw(const Date& date, double amount, const string& desc) { 33 if (amount > getBalance()) { 34 error("not enough money"); 35 } 36 else { 37 record(date, -amount, desc); 38 acc.change(date, getBalance()); 39 } 40 } 41 42 void SavingsAccount::settle(const Date& date) { 43 double interest = acc.getSum(date) * rate / date.distance(Date(date.getYear() - 1, 1, 1)); 44 if (interest != 0)record(date, interest, "interest"); 45 acc.reset(date, getBalance()); 46 } 47 48 CreditAccount::CreditAccount(const Date&date,const string&id,double credit,double rate,double fee):Account(date,id),credit(credit),rate(rate),fee(fee),acc(date,0){} 49 50 void CreditAccount::deposit(const Date& date, double amount, const string& desc) { 51 record(date, amount, desc); 52 acc.change(date, getDebt()); 53 } 54 55 void CreditAccount::withdraw(const Date& date, double amount, const string& desc) { 56 if (amount - getBalance() > credit) { 57 error("not enough credit"); 58 } 59 else { 60 record(date, -amount, desc); 61 acc.change(date, getDebt()); 62 } 63 } 64 65 void CreditAccount::settle(const Date& date) { 66 double interest = acc.getSum(date) * rate; 67 if (interest != 0)record(date, interest, "interest"); 68 if (date.getMonth() == 1) 69 record(date, -fee, "annual fee"); 70 acc.reset(date, getDebt()); 71 } 72 73 void CreditAccount::show()const { 74 Account::show(); 75 cout << "\tAvailable credit:" << getAvailableCredit(); 76 }
7_10.cpp:
1 #include"account.h" 2 #include<iostream> 3 4 using namespace std; 5 6 int main() { 7 Date date(2008, 11, 1); 8 SavingsAccount sa1(date, "S3755217", 0.015); 9 SavingsAccount sa2(date, "02342342", 0.015); 10 CreditAccount ca(date, "C5392394", 10000, 0.0005, 50); 11 12 sa1.deposit(Date(2008, 11, 5), 5000, "salary"); 13 ca.withdraw(Date(2008, 11, 15), 2000, "buy a cell"); 14 sa2.deposit(Date(2008, 11, 25), 10000, "sell stock 0323"); 15 16 ca.settle(Date(2008, 12, 1)); 17 18 ca.deposit(Date(2008, 12, 1), 2016, "repay the credit"); 19 sa1.deposit(Date(2008, 12, 5), 5500, "salary"); 20 21 sa1.settle(Date(2009, 1, 1)); 22 sa2.settle(Date(2009, 1, 1)); 23 ca.settle(Date(2009, 1, 1)); 24 25 cout << endl; 26 sa1.show(); cout << endl; 27 sa2.show(); cout << endl; 28 ca.show(); cout << endl; 29 cout << "Total:" << Account::getTotal() << endl; 30 return 0; 31 }
改进:使用了类的继承,既避免了重复代码,又提高了组织性和结构性,使程序更易于理解和管理。
实验总结:1.通过在类前面加上template<typename T> ,使得定义的X不是一个具体的类,而是一个类模板;
2.使用类模板定义对象时,首先要为类模板的抽象数据类型T提供类型参数,得到具体的类;(实例化)