Comprehensive practice of C + + programming (Zheng Li) in Tsinghua University
preface
In the comprehensive practice of the course, the simulated bank is realized. Users can add savings and credit card accounts and deposit and withdraw money from the accounts. The savings accounts are settled on January 1 every year and the credit card accounts are settled on January 1 every month.
1, Header file
1.date.h
This class is used to record the time in the program. You can enter the format of XXXX XX XX to provide other classes with a method to calculate the number of days between two dates.
#pragma once #ifndef _DATE_H_ #define _DATE_H_ #include<iostream> #include<utility> #include<string> using namespace std; class Date { private: int year; int month; int day; int totalDays;//The day beginning on January 1, A.D public: Date(int year, int month, int day); Date() :year(0), month(0), day(0), totalDays(0) { ; } inline int getYear() const { return year; } inline int getMonth() const { return month; } inline int getDay()const { return day; } inline int getMaxDay() const; bool isLeapYear() const; void show() const; int operator-(const Date& date) const { return this->totalDays - date.totalDays; } //Heavy load< bool operator< (const Date& date) const { if (this->getYear() == date.getYear()) { if (this->getMonth() == date.getMonth()) { return this->getDay() < date.getDay(); } return this->getMonth() < date.getMonth(); } return this->getYear() < date.getYear(); } //Overloaded input stream friend istream& operator >> (istream& in, Date& date); //Overloaded output stream friend ostream& operator << (ostream& out, Date& date); int getCurMonDay() const;//Gets the number of days in the current month }; #endif // _DATE_H_
2.accumulator.h
This class is an auxiliary tool class used to process settlement interest.
#pragma once #ifndef _ACCUMULATOR_H_ #define _ACCUMULATOR_H_ #include"date.h" class Accumulator { private: Date lastDate; double value; //Amount in account double sum;//Daily cumulative sum before the last date public: Accumulator(Date date,double value); double getSum(Date date) const; void change(Date date, double value); void reset(Date date, double value); }; #endif // _ACCUMULATOR_H_
3.account.h
The base class for savings accounts and credit card accounts, which have the same elements. The Detail information class is written in it. This class stores the relevant information obtained by the query, and stores the pipeline information used to query the time range in the multimap. The multimap takes date as the key and the Detail information as the value. Therefore, the < sign needs to be overloaded in the above date class to meet the order of key value pairs in the map.
#ifndef _ACCOUNT_H_ #define _ACCOUNT_H_ #include<iostream> #include<map> #include"date.h" using namespace std; //Operation details class Detail { private: string id; Date da; double v, all; string desc; public: Detail(string id,Date da, double v, double all, string desc) :id(id),da(da), v(v), all(all), desc(desc) { } void show() const{ cout << "account number:" << id << "\t"; da.show(); cout << "\t" << v << "\t" << all << "\t" << desc << endl; } }; typedef multimap<Date, Detail> RecordMap;//Define multiple mappings for storing account records class Account { private: string id;//account number double balance;//balance static double total;//Total amount of all accounts static RecordMap mp;//Static member, only one global member public: //Constructor Account(Date date, string id); inline string getId() const { return id; } inline double getBalance() const { return balance; } inline static double getTotal() { return total; } void record(Date date, double amount, const string& desc); //Display account information virtual void show() const { cout << " " << getId() << "\t" << "Balance: " << getBalance() << endl; }; virtual void deposit(Date date, double amount, const string& desc) = 0; virtual void withdraw(Date date, double amount, const string& desc) = 0; virtual void settle(Date date) = 0;//Pure virtual function, defined in the derived class, is convenient to point to different solutions with the base class pointer void error(string msg) const; //Static member function, time range query static void serach_find(const Date &date1, const Date &date2); }; #endif
4.savingsaccount.h
This class is a savings account class, which contains the creation of savings accounts and the operations of deposit and withdrawal.
#pragma once #ifndef _SAVINGSACCOUNT_H_ #define _SAVINGSACCOUNT_H_ #include<iostream> #include"date.h" #include"account.h" #include"accumulator.h" using namespace std; class savingsAccount :public Account { private: Accumulator acc;//Auxiliary tools double rate;//interest rate public: savingsAccount(Date date, string id, double rate); double getRate() const { return rate; } void deposit(Date date, double amount, const string &desc);//save money void withdraw(Date date, double amount, const string &desc);//Withdraw money void settle(Date date);//Interest settlement }; #endif // !_SAVINGSACCOUNT_H_
5.creditaccount.h
This class is a credit card account class, which contains the creation of credit card accounts and the operations of deposit and withdrawal.
#pragma once #ifndef _CREDITACCOUNT_H_ #define _CREDITACCOUNT_H_ #include<iostream> #include"account.h" #include"accumulator.h" #include"date.h" using namespace std; class creditAccount :public Account{ private: Accumulator acc; double credit, rate, fee;//Credit amount, interest, card fee //Query debt double getDebt() const { return getBalance() < 0 ? getBalance() : 0; } public: creditAccount(Date date, string id, double credit, double rate, double fee); double getCredit() const { return credit; } double getRate() const { return rate; } double getFee() const { return fee; } double getAvailableCredit() const; void deposit(Date date, double amount, const string &desc); void withdraw(Date date, double amount, const string &desc); void settle(Date date);//Called once on the 1st of each month void show() const; }; #endif // !_CREDITACCOUNT_H_
2, Implementation file
1.date.cpp
The calculation method of totalDays is to calculate the number of days from the current storage date to January 1 of the first year each time the object is initialized. 365*(year-1) represents the total number of days in all years except the current year (ordinary years), and then add all leap years during this period, (year-1)/4+(year-1)/400-(year-1)/100. There is a leap every four years in ordinary years and every 400 years in century years, Finally, add the number of days in the current year.
#include"date.h" #Include < cstdlib > / / include exit function namespace {//namespace makes the following definitions valid only in the current file //Stores the number of days before the first day of a month in a normal year, which is convenient for the implementation of the getmaxday function const int DAYS_BEFORM_MONTH[] = { 0,0,31,59,90,120,151,181,212,243,273,304,334 }; const int DAYS[]{ 0,31,28,31,30,31,30,31,31,30,31,30,31 }; }; Date::Date(int year, int month, int day):year(year),month(month),day(day) { if (isLeapYear() && month == 2) { if (day <= 0 || day > 29) { cout << "Invalid date:"; show(); cout << endl; exit(1); } } if (day <= 0 || day > DAYS[month]) { cout << "Invalid date:"; show(); cout << endl; exit(1); } totalDays = 365 * (year - 1) + (year - 1) / 4 - (year - 1) / 100 + (year - 1) / 400 + getMaxDay() + day - 1;//The number of days from the current date to January 1 of the first year //show(); //Cout < < current distance from the first year < < totaldays < < endl; } int Date::getMaxDay() const { if(isLeapYear()&&month>1) return DAYS_BEFORM_MONTH[month]+1; return DAYS_BEFORM_MONTH[month]; } int Date::getCurMonDay() const { return DAYS[this->month]; } bool Date::isLeapYear() const { if ((!(year % 4) && (year % 100)) || !(year % 400)) return true;//Can be divided by 4 but not by 100, or can be divided by 400 return false; } void Date::show() const { cout << year << "-" << month << "-" << day << "\t"; } istream& operator >> (istream& in, Date& date) { char ch; in >> date.year ; in >> ch;//Remove- in >> date.month; in >> ch; in >> date.day; return in; } ostream& operator << (ostream& out, Date& date) { out << date.year << "-" << date.month << "-" << date.day; return out; }
2.accumulator.cpp
The following functions are often called in other classes.
#include"accumulator.h" Accumulator::Accumulator(Date date, double value):lastDate(date),value(value),sum(0){ } //Returns the daily cumulative value of the specified date double Accumulator::getSum(Date date) const { //Cout < < time interval: "< (date - lastdate) < < cumulative sum:" < sum + value * (date - lastdate) < < endl; return sum + value * (date - lastDate); } //change value void Accumulator::change(Date date, double value) {//value is the amount in the account sum = getSum(date);//Calculate the daily cumulative value before this date lastDate = date;//Modify last date this->value = value;//Change current value } void Accumulator::reset(Date date, double value) { lastDate = date; this -> value = value; sum = 0; }
3.account.cpp
When the account information changes, the record function will be called. In this function, the detailed information of each change will be added to the map for future query.
#include"account.h" double Account::total = 0; RecordMap Account::mp ; Account::Account(Date date, string id) :id(id), balance(0) { cout << date << "\t" << "#" << id << " is created " << endl; } void Account::record(Date date, double amount, const string &desc) { //When the balance changes, the cumulative value of the balance is updated amount = floor(amount * 100 + 0.5) / 100;//Keep 2 decimal places balance += amount; total += amount; date.show(); cout << "\t#" << id << "\t" << amount << "\t" << balance << "\t" << desc << endl; //Store the detail information structure as a value // date as key Account::mp.emplace(date, Detail(id,date,amount, balance,desc)); } void Account::error(string msg) const { cout << "The current error message is:" << msg << endl; } void Account::serach_find(const Date& date1, const Date& date2) { auto start = Account::mp.lower_bound(date1);//Find the first detailed information greater than or equal to the date auto over = Account::mp.upper_bound(date2);//Find the first detail greater than this date for (; start != over; start++) { start->second.show(); } }
4.savingsaccount.cpp
This class is a savings account class, which includes the creation and deposit and withdrawal of savings accounts. The savings accounts settle interest on January 1 every year.
#include"savingsaccount.h" #include"accumulator.h" savingsAccount::savingsAccount(Date date, string id, double rate) :Account(date,id), rate(rate),acc(Accumulator(date,0)) {//Call the constructor construction of the base class //Cout < < "# \ T" < < ID < < "\ T" < "savings account creation completed" < < endl; } void savingsAccount::deposit(Date date, double amount, const string& desc) {//deposit record(date, amount, desc); acc.change(date, getBalance());//Change the value in the tool class to the amount in the account } void savingsAccount::withdraw(Date date, double amount, const string& desc) { if (amount <= getBalance()) { record(date, -amount, desc); acc.change(date, getBalance()); } else { cout << "Your account balance is insufficient!" << endl; } } void savingsAccount::settle(Date date) { const double interest = acc.getSum(date) * rate / 365;//annual interest if (interest != 0 && date.getMonth() == 1 && date.getDay() == 1) {//Savings accounts are settled in January each year record(date, interest, "interest"); } acc.reset(date, getBalance());//Recalculate cumulative value }
5.creditaccount.cpp
This class is a credit card account class, which includes the creation of credit card accounts, deposit and withdrawal operations, and interest settlement once a month.
#include"creditaccount.h" //Constructor creditAccount::creditAccount(Date date, string id, double credit, double rate, double fee) : Account(date, id), credit(credit), rate(rate), fee(fee), acc(Accumulator(date, 0)) { //Cout < < "# \ T" < < ID < < "\ T" < "credit card account creation completed" < < endl; } //Get available credit double creditAccount::getAvailableCredit() const { if (getBalance() < 0) { return credit + getBalance();//If there is a liability, return the credit amount minus the liability } return credit; } //There is no interest on saving money void creditAccount::deposit(Date date, double amount, const string& desc) { record(date, amount, desc); acc.change(date, getDebt()); } //There is interest on withdrawal void creditAccount::withdraw(Date date, double amount, const string& desc) { if (amount <= getAvailableCredit()) { record(date, -amount, desc); acc.change(date, getDebt()); } else { cout << "Sorry, your credit is running low" << endl; } } void creditAccount::settle(Date date) { const double interest = acc.getSum(date) * rate;//Monthly interest if (interest != 0 && getAvailableCredit() > -interest) { record(date, interest, "interest"); } //Credit card fee is charged in January every year if (date.getMonth() == 1 && getAvailableCredit() > fee) { record(date, -fee, "Card fee"); } acc.reset(date, getBalance());//Recalculate cumulative value } void creditAccount::show() const { cout << " " << getId() << "\t" << "Balance: " << getBalance() << "\t" << "Current credit card balance:" << getAvailableCredit() << endl; }
3, main method
The above class is tested in the main method, and each input command is stored in the txt file.
#include"account.h" #include"savingsaccount.h" #include"accumulator.h" #include"date.h" #include"creditaccount.h" #include<vector> #include<fstream> using namespace std; int main() { ofstream fout("data.txt");//write in Date date(2008, 11, 1);//The initial time node needs to be updated every time the time is changed. You should first read the time node from the backup file vector<Account*> accounts; Account* acc; std::cout << "Operation:(a)Add users,(d)Deposits,(w)withdraw money,(s)Query account information,(c)Fast forward,(n)Next month,(q)Query all records in the date range,(e)sign out" << endl; while (1) { std::cout << date << "\t Total: " << Account::getTotal() << "\t command> "; char str; cin >> str; if (str == 'a') {//Add user char type; string id; cin >> type >> id;//Account type, s for savings account, c for credit card account if (type == 's') { double rate; cin >> rate; acc = new savingsAccount(date, id, rate); fout << str << " " << type << " " << id << " " << rate << endl; //cout << str << " " << id << " " << type << " " << rate << endl; } else { double credit, fee,rate; cin >> credit >> rate >> fee; acc = new creditAccount(date, id, credit, rate, fee); fout << str << " " << type << " " << id << " " << credit << " " << rate << " " << fee << endl; } accounts.push_back(acc); } else if (str == 'd') {//Deposit: read in account id and deposit amount int idx; double amount; string desc; cin >> idx >> amount; std::getline(cin, desc);//Read one line if (idx >= 0 && idx < accounts.size()) {//Verify subscript validity accounts[idx]->deposit(date, amount, desc); } else { std::cout << "The account was not found, please try again" << endl; } fout << str << " " << idx << " " << amount << " " << desc << endl; } else if (str == 'w') {//Withdraw money, read in id, withdraw amount int idx; double amount; string desc; cin >> idx >> amount; std::getline(cin, desc); if (idx >= 0 && idx < accounts.size()) {//Verify subscript validity accounts[idx]->withdraw(date, amount, desc); } else { std::cout << "The account was not found, please try again" << endl; } fout << str << " " << idx << " " << amount << " " << desc << endl; } else if (str == 's') {//Query all account information for (int i = 0; i < accounts.size(); i++) { std::cout << "[" << i << "]" << "\t"; accounts[i]->show(); } } else if (str == 'c') {//Change the date, read in fast forward to the day, can't go back, can't exceed the maximum date of this month, change the time node int day; cin >> day; if (day < date.getDay()) { std::cout << "You cannot enter a previous date" << endl; } else if(day>date.getCurMonDay()){ std::cout << "Days beyond the month cannot be entered" << endl; } else { date = Date(date.getYear(), date.getMonth(), day); } fout << str << " " << day << endl; } else if (str == 'n') {//Enter the next month, the current is 12:00, enter the next year, calculate the savings account interest on January 1 of each year, and change the time node if (date.getMonth() == 12) { date = Date(date.getYear() + 1, 1, 1);//Enter January 1 of the new year } else { date = Date(date.getYear(), date.getMonth() + 1, 1);//Enter the 1st of next month } for (auto it = accounts.begin(); it != accounts.end(); it++) (*it)->settle(date);//Credit card accounts are settled monthly and savings accounts are settled annually fout << str << endl; } else if (str == 'q') {//Details within the query range Date date1, date2; cin >> date1 >> date2; if (date2 < date1) { std::cout << "The second date must be later than the first date, please re-enter" << endl; } else if (date1.getMonth() <= 0 || date1.getMonth() > 12 || date2.getMonth() <= 0 || date2.getMonth() > 12) { std::cout << "Please enter a valid date" << endl; } else if (date1.getDay() > date1.getCurMonDay() || date2.getDay() > date2.getCurMonDay()) { std::cout << "Please enter a valid date" << endl; } else { Account::serach_find(date1, date2);//Enter two dates (XXXX XX XX) separated by spaces } fout << str << " " << date1 << " " << date2 << endl; } else if (str == 'e') {//Exit program break; } } fout.close(); std::cout << "End time:"; std::cout << date << endl; std::cout << "Total: " << Account::getTotal() << endl; return 0; }
summary
This paper summarizes the comprehensive practice of C + + programming in Tsinghua University. The implementation details may be different from those shown in the class. If you find any problems, you are welcome to point out them and discuss them together. The last eleven or twelve chapters are not fully implemented, such as exception handling problems such as the failure to create a Date class object and how the program continues to run.
The next step is to build a server on Linux, receive the commands from the Windows client, process them on the server, and finally return the results on the client.
All project codes can be found in Github warehouse Get (welcome to start)!