Comprehensive practice of C + + programming (Zheng Li) in Tsinghua University

Posted by doobster on Mon, 10 Jan 2022 15:34:25 +0100

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)!

Topics: C++ Back-end