cpp 實驗4

泽康郁發表於2024-11-17
cpp 實驗4
 1 .hpp
 2 #pragma once
 3 #include<iostream>
 4 #include<vector>
 5 #include<string>
 6 #include<algorithm>
 7 #include<numeric>
 8 #include<iomanip>
 9 using namespace std;
10 class GradeCalc :public vector<int> {
11 public:
12     GradeCalc(const string& cname, int size);
13     void input();
14     void output()const;
15     void sort(bool ascending = false);
16     int min()const;
17     int max()const;
18     float average()const;
19     void info();
20 private:
21     void compute();
22 private:
23     string course_name;
24     int n;
25     vector<int> counts = vector<int>(5, 0);
26     vector<double> rates = vector<double>(5, 0);
27 };
28 GradeCalc::GradeCalc(const string& cname, int size) :course_name{ cname }, n{ size } {}
29 void GradeCalc::input() {
30     int grade;
31     for (int i = 0; i < n; i++) {
32         cin >> grade;
33         this->push_back(grade);
34     }
35 }
36 void GradeCalc::output()const {
37     for (auto ptr = this->begin(); ptr != this->end(); ptr++) {
38         cout << *ptr << " ";
39     }
40     cout << endl;
41 }
42 void GradeCalc::sort(bool ascending) {
43     if (ascending) std::sort(this->begin(), this->end());
44     else std::sort(this->begin(), this->end(), greater<int>());
45 }
46 int GradeCalc::min()const {
47     return *min_element(this->begin(), this->end());
48 }
49 int GradeCalc::max()const {
50     return *max_element(this->begin(), this->end());
51 }
52 float GradeCalc::average()const {
53     return accumulate(this->begin(), this->end(), 0) * 1.0 / n;
54 }
55 void GradeCalc::compute() {
56     for (int grade : *this) {
57         if (grade < 60) counts.at(0)++;
58         else if (grade >= 60 && grade < 70) counts.at(1)++;
59         else if (grade >= 70 && grade < 80) counts.at(2)++;
60         else if (grade >= 80 && grade < 90) counts.at(3)++;
61         else if (grade >= 90)counts.at(4)++;
62 
63     }
64     for (int i = 0; i < rates.size(); i++) {
65         rates.at(i) = counts.at(i) * 1.0 / n;
66     }
67 }
68 void GradeCalc::info() {
69     cout << "課程名稱:\t" << course_name << endl;
70     cout << "排序後課程成績: \t";
71     sort(); output();
72     cout << "最高分:\t" << max() << endl;
73     cout << "最低分:\t" << min() << endl;
74     cout << "平均分:\t" << fixed << setprecision(2) << average() << endl;
75     compute();
76     vector<string> tmp{ "[0,60) ","[60,70)","[70,80)","[80,90)","[90,100]" };
77     for (int i = tmp.size() - 1; i >= 0; i--)
78         cout << tmp[i] << "\t: " << counts[i] << "人\t" << fixed << setprecision(2) << rates[i] * 100 << "%" << endl;
79 }
80 
81 
82 .cpp
83 #include "GradeCalc.hpp"
84 #include<iomanip>
85 void test() {
86     int n;
87     cout << "請輸入班級人數: ";
88     cin >> n;
89     GradeCalc c1("OPP", n);
90     cout << "錄入成績: " << endl;
91     c1.input();
92     cout << "輸出成績: " << endl;
93     c1.output();
94     cout << string(20, '*') + "課程成績資訊" + string(20, '*') << endl;
95     c1.info();
96 }
97 int main() {
98     test();
99 }
task 2

task2
問題1:儲存在它繼承的基類vector中透過public繼承方式繼承的基類中的protected介面訪問每一個成績,和實現資料存入.
問題2:計算this所指向容器所有元素的和並取平均。會。整形資料整除會導致資料小數部分的丟失,乘以1.0將分母轉化成浮點型資料。
問題3:缺乏對輸入資料合法性的判斷,如果輸入的資料中存在不合法的資料,會導致程式執行結果出錯。

cpp 實驗4
  1 .hpp
  2 #pragma once
  3 #include <iostream>
  4 #include <vector>
  5 #include <string>
  6 #include <algorithm>
  7 #include <numeric>
  8 #include <iomanip>
  9 
 10 using std::vector;
 11 using std::string;
 12 using std::cin;
 13 using std::cout;
 14 using std::endl;
 15 
 16 class GradeCalc {
 17 public:
 18     GradeCalc(const string& cname, int size);
 19     void input();                             // 錄入成績
 20     void output() const;                      // 輸出成績
 21     void sort(bool ascending = false);        // 排序 (預設降序)
 22     int min() const;                          // 返回最低分
 23     int max() const;                          // 返回最高分
 24     float average() const;                    // 返回平均分
 25     void info();                              // 輸出課程成績資訊 
 26 
 27 private:
 28     void compute();     // 成績統計
 29 
 30 private:
 31     string course_name;     // 課程名
 32     int n;                  // 課程人數
 33     vector<int> grades;     // 課程成績
 34     vector<int> counts = vector<int>(5, 0);      // 儲存各分數段人數([0, 60), [60, 70), [70, 80), [80, 90), [90, 100]
 35     vector<double> rates = vector<double>(5, 0); // 儲存各分數段比例 
 36 };
 37 
 38 GradeCalc::GradeCalc(const string& cname, int size) : course_name{ cname }, n{ size } {}
 39 
 40 void GradeCalc::input() {
 41     int grade;
 42 
 43     for (int i = 0; i < n; ++i) {
 44         cin >> grade;
 45         grades.push_back(grade);
 46     }
 47 }
 48 
 49 void GradeCalc::output() const {
 50     for (int grade : grades)
 51         cout << grade << " ";
 52     cout << endl;
 53 }
 54 
 55 void GradeCalc::sort(bool ascending) {
 56     if (ascending)
 57         std::sort(grades.begin(), grades.end());
 58     else
 59         std::sort(grades.begin(), grades.end(), std::greater<int>());
 60 
 61 }
 62 
 63 int GradeCalc::min() const {
 64     return *std::min_element(grades.begin(), grades.end());
 65 }
 66 
 67 int GradeCalc::max() const {
 68     return *std::max_element(grades.begin(), grades.end());
 69 }
 70 
 71 float GradeCalc::average() const {
 72     return std::accumulate(grades.begin(), grades.end(), 0) * 1.0 / n;
 73 }
 74 
 75 void GradeCalc::compute() {
 76     for (int grade : grades) {
 77         if (grade < 60)
 78             counts.at(0)++;
 79         else if (grade >= 60 && grade < 70)
 80             counts.at(1)++;
 81         else if (grade >= 70 && grade < 80)
 82             counts.at(2)++;
 83         else if (grade >= 80 && grade < 90)
 84             counts.at(3)++;
 85         else if (grade >= 90)
 86             counts.at(4)++;
 87     }
 88 
 89     for (int i = 0; i < rates.size(); ++i)
 90         rates.at(i) = counts.at(i) * 1.0 / n;
 91 }
 92 
 93 void GradeCalc::info() {
 94     cout << "課程名稱:\t" << course_name << endl;
 95     cout << "排序後成績: \t";
 96     sort();  output();
 97     cout << "最高分:\t" << max() << endl;
 98     cout << "最低分:\t" << min() << endl;
 99     cout << "平均分:\t" << std::fixed << std::setprecision(2) << average() << endl;
100 
101     compute();  // 統計各分數段人數、比例
102 
103     vector<string> tmp{ "[0, 60)  ", "[60, 70)", "[70, 80)","[80, 90)", "[90, 100]" };
104     for (int i = tmp.size() - 1; i >= 0; --i)
105         cout << tmp[i] << "\t: " << counts[i] << "人\t"
106         << std::fixed << std::setprecision(2) << rates[i] * 100 << "%" << endl;
107 }
108 
109 
110 .cpp
111 #include "GradeCalc.hpp"
112 #include <iomanip>
113 
114 void test() {
115     int n;
116     cout << "輸入班級人數: ";
117     cin >> n;
118 
119     GradeCalc c1("OOP", n);
120 
121     cout << "錄入成績: " << endl;;
122     c1.input();
123     cout << "輸出成績: " << endl;
124     c1.output();
125 
126     cout << string(20, '*') + "課程成績資訊" + string(20, '*') << endl;
127     c1.info();
128 }
129 
130 int main() {
131     test();
132 }
task 2

task3
問題1:儲存在類中的私有資料成員vector<int> grades中。直接訪問類中的私有成員grades。
問題2:在某些情況下可以不用繼承基類,而直接將基類作為自定義類的資料元素。

cpp 實驗4
 1 1.
 2 #include<iostream>
 3 #include<string>
 4 #include<limits>
 5 using namespace std;
 6 void test1() {
 7     string s1, s2;
 8     cin >> s1 >> s2;
 9     cout << "s1: " << s1 << endl;
10     cout << "s2: " << s2 << endl;
11 }
12 void test2() {
13     string s1, s2;
14     getline(cin, s1);
15     getline(cin, s2);
16     cout << "s1: " << s1 << endl;
17     cout << "s2: " << s2 << endl;
18 }
19 void test3() {
20     string s1, s2;
21     getline(cin, s1, ' ');
22     getline(cin, s2);
23     cout << "s1: " << s1 << endl;
24     cout << "s2: " << s2 << endl;
25 }
26 int main() {
27     cout << "測試1: 使用標準輸入流物件cin輸入字串" << endl;
28     test1();
29     cout << endl;
30     cin.ignore(numeric_limits<streamsize>::max(), '\n');
31     cout << "測試2: 使用函式getline()輸入字串" << endl;
32     test2();
33     cout << endl;
34     cout << "測試3: 使用函式getline()輸入字串, 指定字串分隔符" << endl;
35     test3();
36 
37 }
38 
39 2.
40 #include<iostream>
41 #include<string>
42 #include<vector>
43 #include<limits>
44 using namespace std;
45 void output(const vector<string>& v) {
46     for (auto& s : v)
47         cout << s << endl;
48 }
49 void test() {
50     int n;
51     while (cout << "Enter n: ", cin >> n) {
52         vector<string> v1;
53         for (int i = 0; i < n; i++) {
54             string s;
55             cin >> s;
56             v1.push_back(s);
57         }
58         cout << "output v1: " << endl;
59         output(v1);
60         cout << endl;
61     }
62     
63 }
64 int main() {
65     cout << "測試: 使用cin多組輸入字串" << endl;
66     test();
67 }
68 
69 
70 3.
71 #include<iostream>
72 #include<string>
73 #include<vector>
74 #include<climits>
75 using namespace std;
76 void output(const vector<string>& v) {
77     for (auto& s : v)
78         cout << s << endl;
79 }
80 void test() {
81     int n;
82     while (cout << "Enter n: ", cin >> n) {
83         vector<string> v2;
84         for (int i = 0; i < n; i++) {
85             string s;
86             getline(cin, s);
87             v2.push_back(s);
88         }
89         cout << "output v2: " << endl;
90         output(v2);
91         cout << endl;
92     }
93 }
94 int main() {
95     cout << "測試: 使用函式getline()多組輸入字串" << endl;
96     test();
97     return 0;
98 }
task 4

task4 在讀取整數(或其他資料型別)時,cin 會讀取輸入,但它不會清除緩衝區中的換行符(即使用者按下Enter鍵時生成的 '\n')。如果你隨後使用 getline() 來讀取字串,getline() 會立即遇到這個換行符並認為輸入已經結束。因此,我們使用 cin.ignore() 來跳過這個換行符,確保後續的 getline() 能正確讀取使用者的字串輸入。

cpp 實驗4
 1 hpp
 2 #pragma once
 3 #include<iostream>
 4 using namespace std;
 5 template<typename T>
 6 class GameResourceManager {
 7 private:
 8     T resouce;
 9 public:
10     GameResourceManager(T Resource):resouce(Resource){}
11     T get()const {
12         return resouce;
13     }
14     void update(T num) {
15         resouce += num;
16         if (resouce < 0) resouce = 0;
17     }
18 
19 };
20 
21 
22 
23 cpp
24 #include "grm.hpp"
25 #include <iostream>
26 
27 using std::cout;
28 using std::endl;
29 
30 void test1() {
31     GameResourceManager<float> HP_manager(99.99);
32     cout << "當前生命值: " << HP_manager.get() << endl;
33     HP_manager.update(9.99);
34     cout << "增加9.99生命值後, 當前生命值: " << HP_manager.get() << endl;
35     HP_manager.update(-999.99);
36     cout << "減少999.99生命值後, 當前生命值: " << HP_manager.get() << endl;
37 }
38 
39 void test2() {
40     GameResourceManager<int> Gold_manager(100);
41     cout << "當前金幣數量: " << Gold_manager.get() << endl;
42     Gold_manager.update(50);
43     cout << "增加50個金幣後, 當前金幣數量: " << Gold_manager.get() << endl;
44     Gold_manager.update(-99);
45     cout << "減少99個金幣後, 當前金幣數量: " << Gold_manager.get() << endl;
46 }
47 
48 
49 int main() {
50     cout << "測試1: 用float型別對類别範本GameResourceManager例項化" << endl;
51     test1();
52     cout << endl;
53 
54     cout << "測試2: 用int型別對類别範本GameResourceManager例項化" << endl;
55     test2();
56 }
task 5

cpp 實驗4
 1 .hpp
 2 #pragma once
 3 #include<iostream>
 4 #include<iomanip>
 5 using namespace std;
 6 class Info {
 7 public:
 8     string nickname;
 9     string contact;
10     string city;
11     int n;
12 public:
13     Info(string nickname_,string contact_,string city_,int n_):nickname(nickname_),contact(contact_),city(city_), n(n_) {}
14     void display()const {
15         cout << string(40, '*') << endl;
16         cout <<  "暱稱:" << "\t" << nickname << endl;
17         cout << "聯絡方式:" << "\t" << contact << endl;
18         cout <<  "所在城市:" << "\t" << city << endl;
19         cout << "預定人數:" << "\t" << n << endl;
20     }
21 };
22 
23 
24 .cpp
25 #include"Info.h"
26 #include<iomanip>
27 #include<vector>
28 const int capacity = 100;
29 int main() {
30     cout << "錄入使用者預約資訊:" << endl;
31     cout << "錄入使用者數:";
32     int n;
33     cin >> n;
34     cout << "暱稱" << "\t" << "聯絡方式(郵箱/手機號)" << "\t" << "所在城市" << "\t" << "預定參加人數" << endl;
35     vector<Info> v;
36     string nickname;
37     string contact;
38     string city;
39     int num;
40     int sum = 0;
41     for (int i = 0; i < n; i++) {
42         cin >> nickname >> contact >> city >> num;
43         sum += num;
44         if (sum > capacity) {
45             char choice;
46             cout << "對不起,只剩" << 100 + num - sum << "個位置" << endl;
47             cout << "1. 輸入u,更新(update)預定資訊" << endl;
48             cout << "2. 輸入q,退出預定" << endl;
49             cout << "你的選擇: ";
50             cin >> choice;
51             if (choice == 'u') {
52                 sum -= num;
53                 cout << "請重新輸入預定資訊" << endl;
54                 cin >> nickname >> contact >> city >> num;
55                 sum += num;
56             }
57             else if(choice=='q') {
58                 continue;
59             }
60         }
61         v.push_back(Info(nickname, contact, city, num));
62     }
63     cout << "截至目前,一共有" << sum << "位聽眾預約。" << "預約聽眾資訊如下:" << endl;
64     for (auto i : v) {
65         i.display();
66     }
67     cout << string(40, '*');
68     return 0;
69 }
task 6

cpp 實驗4
  1 date.h
  2 #pragma once
  3 class Date {
  4 private:
  5     int year;
  6     int month;
  7     int day;
  8     int totalDays;
  9 public:
 10     Date(int year, int month, int day);
 11     int getYear()const { return year; }
 12     int getMonth()const { return month; }
 13     int getDay()const { return day; }
 14     int getMaxDay()const;
 15     bool isLeapYear()const {
 16         return year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
 17     }
 18     void show() const;
 19     int distance(const Date& date)const {
 20         return totalDays - date.totalDays;
 21     }
 22 };
 23 accumulator.h
 24 #pragma once
 25 #include "date.h"
 26 class Accumulator {
 27 private:
 28     Date lastDate;
 29     double value;
 30     double sum;
 31 public:
 32     Accumulator(const Date&date,double value):lastDate(date),value(value),sum{0}{}
 33     double getSum(const Date& date) const {
 34         return sum + value * date.distance(lastDate);
 35     }
 36     void change(const Date& date, double value) {
 37         sum = getSum(date);
 38         lastDate = date;
 39         this->value = value;
 40     }
 41     void reset(const Date& date, double value) {
 42         lastDate = date;
 43         this->value;
 44         sum = 0;
 45     }
 46 };
 47 account.h
 48 #pragma once
 49 #include"date.h"
 50 #include"accumulator.h"
 51 #include<string>
 52 using namespace std;
 53 class Account {
 54 private:
 55     string id;
 56     double balance;
 57     static double total;
 58 protected:
 59     Account(const Date& date, const string &id);
 60     void record(const Date& date, double amount, const string& desc);
 61     void error(const string& msg) const;
 62 public:const string& getId() { return id; }
 63       double getBalance()const { return balance; }
 64       static double getTotal() { return total; }
 65       void show()const;
 66 };
 67 class SavingsAccount:public Account {
 68 private:
 69     Accumulator acc;
 70     double rate;
 71 public:
 72     SavingsAccount(const Date& date, const string& id, double rate);
 73     double getRate() const { return  rate; }
 74     void deposit(const Date& date, double amount, const string& desc);
 75     void withdraw(const Date& date, double amount, const string& desc);
 76     void settle(const Date& date);
 77 };
 78 class CreditAccount :public Account {
 79 private:
 80     Accumulator acc;
 81     double credit;
 82     double rate;
 83     double fee;
 84     double getDebt()const {
 85         double balance = getBalance();
 86         return(balance < 0 ? balance : 0);
 87     }
 88 public:CreditAccount(const Date& date, const string& id, double credit, double rate, double fee);
 89       double getCredit()const { return credit; }
 90       double getRate()const { return rate; }
 91       double getFee() const { return fee; }
 92       double getAvailableCredit()const {
 93           if (getBalance() < 0)return credit + getBalance();
 94           else return credit;
 95       }
 96       void deposit(const Date& date, double amount, const string& desc);
 97       void withdraw(const Date& date, double amount, const string& desc);
 98       void settle(const Date& date);
 99       void show()const;
100 };
101 
102 date.cpp
103 #include"date.h"
104 #include<iostream>
105 #include<cstdlib>
106 using namespace std;
107 namespace {
108     const int DAYS_BEFIRE_MONTH[] = { 0,31,59,90,120,151,181,212,243,273,304 ,334,365 };
109 }
110 Date::Date(int year, int month, int day) :year(year), month(month), day(day) {
111     if (day <= 0 || day > getMaxDay()) {
112         cout << "Invalid date: ";
113         show();
114         cout << endl;
115         exit(1);
116     }
117     int years = year - 1;
118     totalDays = years * 365 + years / 4 - years / 100 + years / 400 + DAYS_BEFIRE_MONTH[month - 1] + day;
119     if (isLeapYear() && month > 2) totalDays++;
120 }
121 int Date::getMaxDay()const {
122     if (isLeapYear() && month == 2)
123         return 29;
124     else return DAYS_BEFIRE_MONTH[month] - DAYS_BEFIRE_MONTH[month - 1];
125 }
126 void Date::show()const {
127     cout << getYear() << "-" << getMonth() << "-" << getDay();
128 }
129 
130 accumulator.cpp
131 #include "account.h"
132 #include <cmath>
133 #include<iostream>
134 using namespace std;
135 double Account::total = 0;
136 Account::Account(const Date& date, const string& id) :id(id), balance(0) {
137     date.show();
138     cout << "\t#" << id << "created" << endl;
139 }
140 void Account::record(const Date& date, double amount, const string& desc) {
141     amount = floor(amount * 100 + 0.5) / 100;
142     balance += amount;
143     total += amount;
144     date.show();
145     cout << "\t#" << id << "\t" << amount << "\t" << balance << "\t" << desc << endl;
146 }
147 void Account::show()const { cout << id << "\tBalance:" << balance; }
148 void Account::error(const string& msg)const {
149     cout << "Error(#" << id << "):" << msg << endl;
150 }
151 SavingsAccount::SavingsAccount(const Date&date,const string &id,double rate):Account(date,id),rate(rate),acc(date,0){}
152 void SavingsAccount::deposit(const Date& date, double amount, const string& desc) {
153     record(date, amount, desc);
154     acc.change(date, getBalance());
155 }
156 void SavingsAccount::withdraw(const Date& date, double amount, const string& desc) {
157     if (amount > getBalance()) {
158         error("not enough money");
159     }
160     else {
161         record(date, -amount, desc);
162         acc.change(date, getBalance());
163     }
164 }
165 void SavingsAccount::settle(const Date& date) {
166     double interest = acc.getSum(date) * rate/date.distance(Date(date.getYear()-1,1,1));
167     if (interest != 0)record(date, interest, "interest");
168     acc.reset(date, getBalance());
169 }
170 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){}
171 void CreditAccount::deposit(const Date& date, double amount, const string& desc) {
172     record(date, amount, desc);
173     acc.change(date, getDebt());
174 }
175 void CreditAccount::withdraw(const Date& date, double amount, const string& desc) {
176     if (amount - getBalance() > credit) {
177         error("not enouogh credit");
178     }
179     else {
180         record(date, -amount, desc);
181         acc.change(date, getDebt());
182     }
183 }
184 void CreditAccount::settle(const Date& date) {
185     double interest = acc.getSum(date) * rate;
186     if (interest != 0) record(date, interest, "interest");
187     if (date.getMonth() == 1)record(date, -fee, "annual fee");
188     acc.reset(date, getDebt());
189 }
190 void CreditAccount::show()const {
191     Account::show();
192     cout << "\tAvailable credit:" << getAvailableCredit();
193 }
194 task7.cpp
195 #include "account.h"
196 #include<iostream>
197 using namespace std;
198 int main() {
199     Date date(2008, 11, 1);
200     SavingsAccount sa1(date, "S3755217", 0.015);
201     SavingsAccount sa2(date, "02342342", 0.015);
202     CreditAccount ca(date, "C5392394", 10000, 0.0005, 50);
203     sa1.deposit(Date(2008, 11, 5), 5000, "Salary");
204     ca.withdraw(Date(2008, 11, 15), 2000, "buy a cell");
205     sa2.deposit(Date(2008, 11, 25), 10000, "sell stock 0323");
206     ca.settle(Date(2008, 12, 1));
207     ca.deposit(Date(2008, 12,1), 2016, "repay the credit");
208     sa1.deposit(Date(2008, 12, 5), 5500, "salary");
209     sa1.settle(Date(2009, 1, 1));
210     sa2.settle(Date(2009, 1, 1));
211     ca.settle(Date(2009, 1, 1));
212     cout << endl;
213     sa1.show(); cout << endl;
214     sa2.show(); cout << endl;
215     ca.show(); cout << endl;
216     cout << "Total: " << Account::getTotal() << endl;
217     return 0;
218 
219 }
task 7

task7
1.定義一個基類,account,並從基類繼承得到了兩個派生類SavingAccounts和CreditAccounts.
2.抽象出了一個新的類accumulator專門用於計算銀行賬戶存款的積累.
不足:雖然派生類中有相同的成員函式,deposit,withdraw,settle,但是由於實現不同只能在各自派生類中定義。

相關文章