C++程序设计原理与实践 习题答案 第九章 第9章习题答案

9.2 和 9.3

/*
设计并实现一个保存(name, age)对的Name_pairs类,名字是string,年龄是double。
*/

#include"../../std_lib_facilities.h"

void clear_line();

class Name_pairs {
public:
	Name_pairs();	//默认构造函数
	void read_name();
	void read_age();
	void print() const;
	void sort();
	size_t size() const;
	const string& get_name(size_t index) const;
	const double& get_age(size_t index) const;

private:
	vector<string>name;
	vector<double>age;
	int cnt_pairs();
	int find_index(const vector<string>&, const string&);
};

Name_pairs::Name_pairs()
{
}

int Name_pairs::cnt_pairs()
{
	cout << "Enter the number of names you want input\n";
	int n{ 0 };
	while (cin)
	{
		cin >> n;
		if (n <= 0)
		{
			clear_line();
			cout << "Uncorrect number, enter the number of names you want input\n";
			continue;
		}
		else
			break;
	}

	clear_line();
	return n;
}

int Name_pairs::find_index(const vector<string>& vs, const string& s)
{
	int i;
	for (i = 0; i < vs.size(); i++)
		if (s == vs[i])
			return i;
	error("name not found: ", s);
}

void Name_pairs::read_name()
{
	int n = cnt_pairs();	//获得要读入的名字年龄对数量

	cout << "Enter " << n << " names, or enter ! to quit\n";
	
	string s;
	for (int i = 0; i < n; i++)
	try
	{
		cin >> s;
		if (!cin)
			error("Uncorrect name.");
		else if (s == "!")
			break;
		name.push_back(s);
	}
	catch (runtime_error& e)
	{
		clear_line();
		cerr << e.what() << " You should enter correct name\n";
	}
	//clear_line();
}

void Name_pairs::read_age()
{
	cout << "Enter age for each name\n";
	int n = name.size();
	double d{ 0.0 };

	for(int i = 0; i < n; i++)
	try
	{
		cout << name[i] << ": ";
		cin >> d;
		if (d <= 0)
			error("Uncorrect age.");
		age.push_back(d);
		clear_line();
	}
	catch (runtime_error& e)
	{
		clear_line();
		cerr << e.what() << " You should enter correct age\n";
	}
}

void Name_pairs::print() const
{
	int n = name.size();
	for (int i = 0; i < n; i++)
		cout << '(' << name[i] << ", " << age[i] << ')' << endl;
}

void Name_pairs::sort()
{
	vector<string>original_name = name;
	vector<double>original_age = age;

	std::sort(name.begin(), name.end());
	for (int i = 0; i < name.size(); i++)
		age[i] = original_age[find_index(original_name, name[i])];
}

size_t Name_pairs::size() const
{
	return name.size();
}

const string& Name_pairs::get_name(size_t index) const
{
	return name[index];
}

const double& Name_pairs::get_age(size_t index) const
{
	return age[index];
}

ostream& operator<<(ostream& os, const Name_pairs& np)
{
	for(int i = 0; i < np.size(); i++)
		os << '(' << np.get_name(i) << ", " << np.get_age(i) << ')' << endl;
	return os;
}

bool operator==(const Name_pairs& np1, const Name_pairs& np2)
{
	if (np1.size() != np2.size())
		return false;
	for (int i = 0; i < np1.size(); i++)
	{
		if (np1.get_name(i) != np2.get_name(i))
			return false;
		if (np1.get_age(i) != np2.get_age(i))
			return false;
	}
	return true;
}

bool operator!=(const Name_pairs& np1, const Name_pairs& np2)
{
	return !(np1 == np2);
}

int main()
try
{
	Name_pairs np;
	Name_pairs np2;

	np.read_name();
	np.read_age();
	np.sort();
	//np.print();
	cout << np;

	np2.read_name();
	np2.read_age();
	np2.sort();
	np2.print();

	cout << "name pairs 1" << ((np == np2) ? " == " : " != ") << "name pairs 2" << endl;

	return 0;
}
catch (runtime_error& e)
{
	cerr << "Runtime error: " << e.what() << endl;
	return 1;
}
catch (...)
{
	cerr << "Exception occured!" << endl;
	return 2;
}

//辅助函数
void clear_line()
{
	char c;
	while (cin.get(c) && c != '\n')
		continue;
}

9.5 到 9.9

这个我没有很仔细的测试,应该是有bug的,如果发现bug或者有更好的程序设计方法,请不吝赐教

Library.h头文件

#include"../../std_lib_facilities.h"
#include"Chrono (Date).h"

namespace MyLibrary {
	enum class Genre {
		fiction, nonfiction, periodical,
		biography, children
	};
	vector<string>Genre_tbl{
		"Fiction", "Nonfiction", "Periodical",
		"Biography", "Children"
	};

	class Invalid {};	//用于抛出异常

	class Book {
	public:
		Book();
		Book(string isbn, string bkname, string author, Genre gen);
		string get_isbn() const;
		string get_bkname() const;
		string get_author() const;
		Genre get_genre() const;
		bool lend_book();
		bool ret_book();
	private:
		string isbn;
		string bkname;
		string author;
		Genre gen;
		//版权日期暂时不实现
		bool is_borrowed;
	};

	class Patron {
	public:
		Patron();
		Patron(string name, string id);
		string get_ptname() const;
		string get_ptid() const;
		double get_late_fee() const;
		void set_late_fee(double fee);
	private:
		string reader_name;
		string reader_id;
		double late_fee;
	};

	struct Transaction {
	public:
		Transaction() {}
		Transaction(Book, Patron, Chrono::Date);
	private:
		Book bk;
		Patron reader;
		Chrono::Date lend_date;
	};

	class Library {
	public:
		Library() {};
		void add_book(string isbn, string bkname,
			string author, Genre gen);
		void add_reader(string reader_name, string reader_id);
		int find_book(string isbn, string bkname);
		int find_reader(string reader_name, string reader_id);
		bool lend_book(string bkname, string isbn, string reader_name, string reader_id);
		vector<string> overdue_readers();
	private:
		vector<Book>bookshelf;
		vector<Patron>readers;
		vector<Transaction>trans;
	};


	//辅助函数
	bool is_isbn(const string& isbn);
	bool operator==(Book bk1, Book bk2);
	bool operator!=(Book bk1, Book bk2);
	ostream& operator<<(ostream& os, Book bk);

	bool is_late(const Patron& reader);
}	// MyLibrary

Library.cpp源文件


#include"Library.h"

namespace MyLibrary {

	//class Book
	Book::Book()
		:isbn{ "None" }, bkname{"None"}, author{"None"},
		gen{Genre::nonfiction},  is_borrowed{false}
	{
	}

	Book::Book(string isbn, string bkname, string author, Genre gen)
		:isbn{isbn}, bkname{bkname}, author{author}, 
		gen{gen}, is_borrowed{ false }
	{
		if (!is_isbn(isbn))
			throw Invalid{};
	}

	string Book::get_isbn() const
	{
		return isbn;
	}

	string Book::get_bkname() const
	{
		return bkname;
	}

	string Book::get_author() const
	{
		return author;
	}

	Genre Book::get_genre() const
	{
		return gen;
	}

	bool Book::lend_book()
	{
		if (is_borrowed)
			return false;
		else
		{
			is_borrowed = true;	//表示借出
			return true;
		}
	}

	bool Book::ret_book()
	{
		if (!is_borrowed)
			return false;
		else
		{
			is_borrowed = false;	//表示归还
			return true;
		}
	}

	//Class Book end



	//Class Patron
	Patron::Patron()
		:reader_name{"None"}, reader_id{"None"}, late_fee{0.0}
	{
	}

	Patron::Patron(string name, string id)
		:reader_name{ name }, reader_id{ id }, late_fee{ 0.0 }
	{
	}

	string Patron::get_ptname() const
	{
		return reader_name;
	}

	string Patron::get_ptid() const
	{
		return reader_id;
	}

	double Patron::get_late_fee() const
	{
		return late_fee;
	}

	void Patron::set_late_fee(double fee)
	{
		if (fee < 0)
			throw Invalid{};
		late_fee = fee;
	}
	
	//Class Patron end


	//struct Transaction
	Transaction::Transaction(Book book, Patron patron, Chrono::Date date)
		:bk{ book }, reader{ patron }, lend_date{date}
	{
	}
	//struct Transaction end

	//Class Library
	void Library::add_book(string isbn, string bkname, string author, Genre gen)
	{
		bookshelf.push_back(Book{ isbn,bkname,author,gen });
	}

	void Library::add_reader(string reader_name, string reader_id)
	{
		readers.push_back(Patron{ reader_name, reader_id });
	}

	int Library::find_book(string isbn, string bkname)
	{
		//if find, return index, otherwise return -1
		int i{ 0 };	//book index

		for (Book bk : bookshelf)
			if (bkname == bk.get_bkname() && bk.get_isbn() == isbn)
				return i;
			else
				++i;

		return -1;
	}

	int Library::find_reader(string reader_name, string reader_id)
	{
		//if find, return index, otherwise return -1
		int i{ 0 };	//book index
		
		for (Patron reader : readers)
			if (reader_id == reader.get_ptid() && reader_name == reader.get_ptname())
				return i;
			else
				++i;

		return -1;
	}

	bool Library::lend_book(string bkname, string isbn, string reader_name, string reader_id)
	{
		Book bk = {};
		Patron reader{};
		int book_index{ -1 }, reader_index{ -1 };

		book_index = find_book(isbn, bkname);
		reader_index = find_reader(reader_name, reader_id);

		if (book_index < 0 || reader_index < 0)
			throw Invalid{};
		
		bk = bookshelf[book_index];
		reader = readers[reader_index];

		if (is_late(reader))	//如果欠费
			throw Invalid{};

		//获得当前的年月日
		time_t now = time(0);
		tm* ltm = localtime(&now);
		Chrono::Date date{1900+ltm->tm_year, Chrono::int_to_month(ltm->tm_mon), ltm->tm_mday};

		trans.push_back(Transaction{ bk,reader,date });

		return false;
	}

	vector<string> Library::overdue_readers()
	{
		vector<string>ovd;

		for (Patron reader : readers)
			if (is_late(reader))
				ovd.push_back(reader.get_ptname());
		return ;
	}
	
	//Class Library end
	


	//辅助函数
	bool is_isbn(const string& isbn)
	{
		//isbn格式 n-n-n-x,n为整数,x为整数或者字母
		constexpr size_t isbn_size{ 7 };
		if (isbn.size() != isbn_size)
			return false;
		
		size_t i = 0;
		while (i < isbn_size-1)
		{
			if (!isdigit(isbn[i++]))
				return false;
			if (isbn[i++] != '-')
				return false;
		}
		if (isalnum(isbn[i]))
			return true;
		else
			return false;
	}

	bool operator==(Book bk1, Book bk2)
	{
		return bk1.get_isbn() == bk2.get_isbn();
	}

	bool operator!=(Book bk1, Book bk2)
	{
		return bk1.get_isbn() != bk2.get_isbn();
	}

	ostream& operator<<(ostream& os, Book bk)
	{
		os << bk.get_bkname() << '\n'
			<< bk.get_author() << '\n'
			<< bk.get_isbn() << '\n'
			<< Genre_tbl[int(bk.get_genre())];
		return os;
	}

	bool is_late(const Patron& reader)
	{
		if (reader.get_late_fee() > 0)
			return true;
		else
			return false;
	}

}	// MyLibrary


int main()
try
{
	using MyLibrary::Book;
	using MyLibrary::Genre;
	Book book1{ "1-1-1-a", "Programming", string("Bjarne"), Genre::nonfiction};

	cout << book1 << endl;
	

	return 0;
}
catch (runtime_error& e)
{
	cerr << "Runtime error: " << e.what() << endl;
	return 1;
}
catch (...)
{
	cerr << "Exception occured!" << endl;
	return 2;
}

9.10 到 9.12

实现了书上的Chrono 命名空间中的 (Date) 类 以及辅助函数,不过 add_month 没有成功实现

Chrono.h 头文件

// Chrono.h

#include<iostream>

namespace Chrono {
	enum class Month {
		jan = 1, feb, mar, apr, may, jun,
		jul, aug, sep, oct, nov, dec
	};

	enum class Day {
		sunday, monday, tuesday, wednesday,
		thursday, friday, saturday
	};

	class Date {
	public:
		Date();		//默认构造函数
		Date(int y, Month m, int d);
		Date(int y);

		class Invalid {};

		//注意这些const成员函数,表明这个成员函数可以在常量对象上调用,且编译器会帮我们保证成员函数不会修改对象
		int year() const { return y; }
		Month month() const { return m; }
		int day() const { return d; }

		void add_year(int n);
		void add_month(int n);
		void add_day(int n);

	private:
		int y;
		Month m;
		int d;
	};


	//辅助函数
	const Date& default_date();	//用于设置和返回默认值
	bool leapyear(int y); //判断是否是闰年
	bool is_date(int y, Month m, int d);
	Month int_to_month(int x);
	static int days_until_month(Month m);
	int days_in_year(const Date& d);
	int days_in_month(int y, Month m);
	static int leaps(int years);
	int linear_day(const Date& d);
	Day day_of_week(const Date& d);
	int week_of_year(const Date& d);
	Date next_workday(const Date& d);
	Date next_sunday(const Date& d);

	//关于Date类的运算符重载
	bool operator==(const Date& a, const Date& b);
	bool operator!=(const Date& a, const Date& b);
	std::ostream& operator<<(std::ostream& os, const Date& dd);
	std::istream& operator>>(std::istream& is, Date& dd);
	Date operator+(const Date& date, int add);
	int operator-(const Date& d1, const Date& d2);

	//关于Day类的运算符重载
	std::ostream& operator<<(std::ostream& os, Day d);
}

Chrono.cpp源文件

#include"../../std_lib_facilities.h"
#include"Chrono (Date).h"

namespace Chrono {

	Date::Date()
		:y{ default_date().year() },
		m{ default_date().month() },
		d{ default_date().day() }
	{
	}

	Date::Date(int yy, Month mm, int dd)
		:y{ yy }, m{ mm }, d{ dd }
	{
		if (!is_date(yy,mm,dd))
			throw Invalid{};
	}

	Date::Date(int yy)
		:y{ yy }, m{ default_date().month() },
		d{ default_date().day() }
	{
		if (!is_date(yy, m, d))
			throw Invalid{};
	}

	void Date::add_year(int n)
	{
		if (m == Month::feb && d == 29 && !leapyear(y + n))
		{
			m = Month::mar;
			d = 1;
		}
		y += n;
	}

	void Date::add_month(int n)
	{
		//这样的简单实现是不对的
		if (n < 1)
			throw Invalid{};
		int new_m = int(m) + n;
		if (new_m > 12)
		{
			add_year(new_m / 12);
			new_m %= 12;
		}
		m = Month(new_m);
	}

	void Date::add_day(int n)
	{
		if(n < 1)
			throw Invalid{};

		int new_d = d + n;
		int dim = days_in_month(y, m);
		
		while (new_d > dim)
		{
			new_d -= dim;
			add_month(1);
			dim = days_in_month(y, m);
		}
		d = new_d;
	}


	//以下是辅助函数,用于设置和返回默认值
#define WeekDays 7
	const Date first_date(1601, Month::jan, 1);		//日历计算器从1601年1月1日开始
	const Day first_day = Day::monday;				//这一天是星期一


	const Date& default_date()
	{
		static Date dd{ 2001, Month::jan, 1 };
		return dd;
	}

	int days_in_month(int y, Month m)
	{
		int dim = 31;

		switch (m) {
		case Month::feb:
			dim = leapyear(y) ? 29 : 28;
			break;
		case Month::apr: case Month::jun:
		case Month::sep: case Month::nov:
			dim = 30;
		default:
			break;
		}
		return dim;
	}

	bool is_date(int y, Month m, int d)
	{
		if (d < 1)
			return false;
		
		if (m < Month::jan || m > Month::dec)	//该检查似乎没有必要
			return false;

		if (d > days_in_month(y,m))
			return false;

		return true;
	}

	//辅助函数,判断是否是闰年
	bool leapyear(int y)
	{
		if (y % 4)
			return false;
		else if (y % 100 == 0 && y % 400)
			return false;
		else
			return true;
	}


	Month int_to_month(int x)
	{
		if (x < int(Month::jan) || x > int(Month::dec))
			error("bad month");
		return Month(x);
	}


	static int days_until_month(Month m)
	{
		//返回这个月之前在这一年中过了多少天
		switch (m) 
		{
		case Month::jan:	return 0;
		case Month::feb:	return 31;
		case Month::mar:	return 31 + 28;		//暂时忽略闰年
		case Month::apr:	return 31 + 28 + 31;
		case Month::may:	return 31 + 28 + 31 + 30;
		case Month::jun:	return 31 + 28 + 31 + 30 + 31;
		case Month::jul:	return 31 + 28 + 31 + 30 + 31 + 30;
		case Month::aug:	return 31 + 28 + 31 + 30 + 31 + 30 + 31;
		case Month::sep:	return 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31;
		case Month::oct:	return 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30;
		case Month::nov:	return 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31;
		case Month::dec:	return 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30;
		default:
			error("Invalid month");
		}
	}

	int days_in_year(const Date& d)
	{
		//计算该日期在其所在的年中过了多少天
		int days{ d.day() };
		days += days_until_month(d.month());
		if (d.month() > Month::feb && leapyear(d.year()))
			++days;
		return days;
	}

	static int leaps(int year)
	{
		//变量year表示目前是几几年,函数计算从开始日期,到year年共有多少个闰年
		const int years = year - first_date.year();
		return years / 4 - years / 100 + years / 400;
	}

	int linear_day(const Date& d)
	{
		//计算从first_date开始到日期d,共过了多少天
		int years{ 0 };
		int days{ 0 };

		years = d.year() - first_date.year();
		if (years < 0) 
			error("linear_day: can't handle days before (1601,jan,1)");
		days = years * 365 + leaps(d.year()) + days_in_year(d);

		return days - 1;	//减1是因为对于1601年1月1号,那是同一天,只能算0天。
	}

	Day day_of_week(const Date& d)
	{
		int days = int(first_day) + linear_day(d);
		return Day(days % WeekDays);
	}

	int week_of_year(const Date& d)
	{
		//假定第一周是1月1日所在那周,每周的第1天是周日
		int days_year = days_in_year(d);
		Day first_day_of_year = day_of_week(Date{d.year(),Month::jan,1});
		return (days_year + int(first_day_of_year) - 1) / 7 + 1;
	}

	Date next_workday(const Date& d)
	{
		Day today = day_of_week(d);
		int to_next_workday{ 1 };

		switch (today)
		{
		case Day::friday: 
			to_next_workday = 3;
			break;
		case Day::saturday:
			to_next_workday = 2;
			break;
		default:
			break;
		}
		return d + to_next_workday;
	}

	Date next_sunday(const Date& d)
	{
		Day dd = day_of_week(d);
		Date ns = d;
		return d + (7 - int(dd));

	}

	//关于Date的运算符重载
	bool operator==(const Date& a, const Date& b)
	{
		return a.year() == b.year()
			&& a.month() == b.month()
			&& a.day() == b.day();
	}

	bool operator!=(const Date& a, const Date& b)
	{
		return !(a == b);
	}

	std::ostream& operator<<(std::ostream& os, const Date& dd)
	{
		return os << '(' << dd.year()
			<< ',' << int(dd.month())
			<< ',' << dd.day() << ')';
	}

	std::istream& operator>>(std::istream& is, Date& dd)
	{
		int y, m, d;
		char ch1, ch2, ch3, ch4;
		
		is >> ch1 >> y >> ch2 >> m >> ch3 >> d >> ch4;
		if (!is)
			return is;
		if (ch1 != '(' || ch2 != ',' || ch3 != ',' || ch4 != ')')
		{
			is.clear(std::ios_base::failbit);
			return is;
		}
		dd = Date{ y,Month(m),d };
		return is;
	}

	Date operator+(const Date& date, int add)
	{
		Date new_date = date;
		new_date.add_day(add);
		return new_date;
	}

	int operator-(const Date& d1, const Date& d2)
	{
		int days1 = linear_day(d1);
		int days2 = linear_day(d2);
		return days1 - days2;
	}

	//关于Day的运算符重载
	std::ostream& operator<<(std::ostream& os, Day d)
		// sloppy: I should have used a table
	{
		switch (d) {
		case Day::sunday:
			os << "Sunday";
			break;
		case Day::monday:
			os << "Monday";
			break;
		case Day::tuesday:
			os << "Tuesday";
			break;
		case Day::wednesday:
			os << "Wednesday";
			break;
		case Day::thursday:
			os << "Thursday";
			break;
		case Day::friday:
			os << "Friday";
			break;
		case Day::saturday:
			os << "Saturday";
			break;
		}
		return os;
	}
}

main.cpp 测试 Chrono Date

#include"../../std_lib_facilities.h"
#include"Chrono (Date).h"

int zxc;

void write(const Chrono::Date& d)	// debug output function
{
	cout << d << ": " << day_of_week(d) << "; linear: " << linear_day(d) << "; of week #" << week_of_year(d) << '\n';
}

int main()
try
{
	Chrono::Date xxx(2001, Chrono::Month::jan, 1);
	write(xxx);
	Chrono::Date xxxw = next_workday(xxx);
	write(xxxw);

	Chrono::Date xx(2001, Chrono::Month::jan, 8);
	write(xx);
	Chrono::Date xxw = next_workday(xx);
	write(xxw);

	Chrono::Date today(2010, Chrono::Month::jan, 16);
	write(today);
	Chrono::Date todayw = next_workday(today);
	write(todayw);

	Chrono::Date vote(2010, Chrono::Month::mar, 13);
	write(vote);
	Chrono::Date votew = next_workday(vote);
	write(votew);

	using namespace Chrono;
	cout << "enter some dates: ";
	Date d;
	while (cin >> d) {
		write(d);
	}

	keep_window_open("~");	// For some Windows(tm) setups
}
catch (Chrono::Date::Invalid&) {
	cerr << "error: Invalid date\n";
	keep_window_open("~");	// For some Windows(tm) setup
	return 1;
}
catch (runtime_error& e) {	// this code is to produce error messages
	cout << e.what() << '\n';
	keep_window_open("~");	// For some Windows(tm) setups
}

/*
	This has not been SYSTEMATICALLY tested, so you should be able to find bugs;
	I'd like to hear about those.

*/

9.13 Rational 类

#include"../../std_lib_facilities.h"

unsigned int gcd(unsigned int m, unsigned int n);	//欧几里得算法求最大公因数

class Rational {
public:
	Rational() :numerator{ 0 }, denominator{ 1 }{ }
	Rational(int n, int d)
		:numerator{ n }, denominator{ d }
	{	normalize();	}
	int get_num() const;
	int get_den() const;
private:
	int numerator;
	int denominator;
	void normalize();
};

void Rational::normalize()
{
	//使有理数的分母为正数,并使分子与分母互素(即两者最大公因数为1)
	if(denominator == 0)
		error("denominator can not be zere");
	if (denominator < 0)
		numerator = -numerator;
	
	unsigned int temp_num = (numerator < 0 ? -numerator : numerator);
	int nm_gcd = gcd(temp_num, denominator);
	if (nm_gcd != 1)
	{
		numerator /= nm_gcd;
		denominator /= nm_gcd;
	}
}

int Rational::get_num() const
{
	return numerator;
}

int Rational::get_den() const
{
	return denominator;
}


//算术运算符重载
Rational operator+(const Rational& op1, const Rational& op2)
{
	int den1 = op1.get_den();
	int den2 = op2.get_den();
	int den = den1 * den2;
	int num = op1.get_num() * den2 + op2.get_num() * den1;
	if (num == 0)
		return Rational();
	else
		return Rational(num, den);
}

Rational operator-(const Rational& op1, const Rational& op2)
{
	int den1 = op1.get_den();
	int den2 = op2.get_den();
	int den = den1 * den2;
	int num = op1.get_num() * den2 - op2.get_num() * den1;
	if (num == 0)
		return Rational();
	else
		return Rational(num, den);
}

Rational operator-(const Rational& r)
{
	//取负数
	if (r.get_num() == 0)
		return Rational();
	else
		return Rational(-r.get_num(), r.get_den());
}

Rational operator*(const Rational& op1, const Rational& op2)
{
	int den = op1.get_den() * op2.get_den();
	int num = op1.get_num() * op2.get_num();
	if (num == 0)
		return Rational();
	else
		return Rational(num, den);
}

Rational operator/(const Rational& op1, const Rational& op2)
{
	int num2 = op2.get_num();
	if (num2 == 0)
		error("divided by zero");
	
	int den = op1.get_den() * op2.get_num();
	int num = op1.get_num() * op2.get_den();
	if (num == 0)
		return Rational();
	else
		return Rational(num, den);
}

//逻辑运算符重载
bool operator==(const Rational& op1, const Rational& op2)
{
	return (op1.get_num() == op2.get_num())
		&& (op1.get_den() == op2.get_den());
}

bool operator!=(const Rational& op1, const Rational& op2)
{
	return (op1.get_num() != op2.get_num())
		|| (op1.get_den() != op2.get_den());
}

//IO运算符重载
ostream& operator<<(ostream& os, const Rational& r)
{
	if (r.get_num() == 0)
		os << 0;
	else
		os << '(' << r.get_num() << '/' << r.get_den() << ')';
	return os;
}

//辅助函数
unsigned int gcd(unsigned int m, unsigned int n)
{
	/*欧几里得算法求最大公因数
	  假设 m >= n,如果不是,则第一次迭代会将它们互换 
	*/
	unsigned int rem{ 0 };
	while (n > 0)
	{
		rem = m % n;
		m = n;
		n = rem;
	}
	return m;
}

double r2d(const Rational& r)
{
	//将有理数转换为整数
	return double(r.get_num()) / r.get_den();
}


/*
	How do we test all that?

	The simplest is to compute a number of values using Rational and double and see if
	we get roughly the same results; if so we are not far off. That's a variant of the
	time honored and often elegant technique of calculating something in two different
	ways and then comparing the results.

	What you see below is *not* exhaustive, thorough, or sufficient testing. Please try some more.
*/

int main()
try
{
	Rational r1(4, 2);
	cout << r1 << "==" << r2d(r1) << '\n';
	Rational r2(42, 24);
	cout << r2 << "==" << r2d(r2) << '\n';
	cout << r1 + r2 << "==" << r2d(r1 + r2) << "==" << r2d(r1) + r2d(r2) << '\n';
	cout << r1 - r2 << "==" << r2d(r1 - r2) << "==" << r2d(r1) - r2d(r2) << '\n';
	cout << -r2 << "==" << r2d(-r2) << "==" << -r2d(r2) << '\n';
	cout << r1 * r2 << "==" << r2d(r1 * r2) << "==" << r2d(r1) * r2d(r2) << '\n';
	cout << r1 / r2 << "==" << r2d(r1 / r2) << "==" << r2d(r1) / r2d(r2) << '\n';
	if (r2 == Rational(14, 8)) cout << "equal\n";
	if (r2 != Rational(14, 8)) cout << "not equal\n";
	Rational(3, 0);	// we're out of here!

	keep_window_open("~");	// For some Windows(tm) setups
}
catch (runtime_error e) {	// this code is to produce error messages; it will be described in Chapter 5
	cout << e.what() << '\n';
	keep_window_open("~");	// For some Windows(tm) setups
}
catch (...) {	// this code is to produce error messages; it will be described in Chapter 5
	cout << "exiting\n";
	keep_window_open("~");	// For some Windows(tm) setups
}

/*
	Why would anyone use rational numbers? Well, floating point is imprecise (e.g. can't represent a third
	exactly) and some things are for good and/or legal reasons required to be exact (e.g. financial calculations).
*/

9.14 到 9.16 Money类

#include"../../std_lib_facilities.h"


struct Exchg_rate {
	string cur;
	double rate;
	Exchg_rate(string s, double r) :cur{ s }, rate{ r }{ }
};

vector<Exchg_rate>er = {
	Exchg_rate{"DKK", 6.2842},Exchg_rate{"CNY", 6.4424},
	Exchg_rate{"EUR", 0.8452}
};

class Money {
	long int cent;	//用美分表示金额
	string currency;
public:
	Money() :cent{ 0 }{ }
	Money(string cur_name, long int c) :cent{ c }, currency{cur_name} { }
	Money(double dollar);
	Money(string cur_name, double dollar);
	
	double sum() const;
	string get_cur() const;
};

Money::Money(double dollar)
	:cent{ long((dollar + 0.005) * 100) }, currency{"USD"}
{
	if (dollar < 0)
		error("Money can not be negative");
	dollar += 0.005;	//为了四舍五入操作
	if (dollar * 100 > double(LONG_MAX))
		error("imprecise");	
}

Money::Money(string cur_name, double dollar)
	:cent{ long((dollar + 0.005) * 100) }, currency{ cur_name }
{
	if (dollar < 0)
		error("Money can not be negative");
	dollar += 0.005;	//为了四舍五入操作
	if (dollar * 100 > double(LONG_MAX))
		error("imprecise");

}

double Money::sum() const
{
	return double(cent) / 100;
}

string Money::get_cur() const
{
	return currency;
}

istream& operator>>(istream& is, Money& m)
{
	char ch;	
	string cur;	//currency
	double d;
	
	while (is >> ch)
	{
		if (isdigit(ch) || ch == '.')
			break;
		cur += ch;
	}
	is.putback(ch);
	is >> d;
	if (!is)
		return is;

	//if (cur)		//格式错误
	//{
	//	is.clear(ios_base::failbit);
	//	return is;
	//}

	m = Money{ cur, d };
	return is;
}

ostream& operator<<(ostream& os, const Money& m)
{
	os << m.get_cur() << m.sum();
	return os;
}

Money operator+(const Money& m1, const Money& m2)
{
	/*操作逻辑:
		如果两个货币都是一样的单位,那么简单相加
		如果两个货币中的一个是美元,那么按照美元算
		如果两个货币都不是美元,那么按第一个货币算
	*/
	string c1 = m1.get_cur();
	string c2 = m2.get_cur();

	if (c1 == c2)
		return Money{ c1, m1.sum() + m2.sum() };
	else if (c1 == "USD")
	{
		for (Exchg_rate e : er)
			if (e.cur == c2)
				return Money{ m1.sum() + m2.sum() / e.rate };
		error("No exchange rate");
	}
	else if (c2 == "USD")
	{
		for (Exchg_rate e : er)
			if (e.cur == c2)
				return Money{ m1.sum() + m2.sum() / e.rate };
		error("No exchange rate");
	}
	else
	{
		for(Exchg_rate e1:er)
			if (e1.cur == c1)
			{
				for (Exchg_rate e2 : er)
					if (e2.cur == c2)
					{
						double add_sum = m1.sum() + m2.sum() / e2.rate * e1.rate;
						return Money{ c1, add_sum };
					}
				error("No exchange rate");
			}
		error("No exchange rate");
	}
}

int main()
try
{
	Money m1{ 12 };
	cout << m1 << endl;

	Money m2{"DKK", 5.125};
	//cin >> m2;
	cout << m2 << endl;

	cout << m1 + m2 << endl;

	Money m3{ "CNY", 7.365 };
	cout << m1 + m3 << endl;
	cout << m2 + m3 << endl;

	Money m4;
	cin >> m4;
	cout << m4;

	return 0;
}
catch (runtime_error& e)
{
	cerr << "Runtime error: " << e.what() << endl;
	return 1;
}
catch (...)
{
	cerr << "Exception occured!" << endl;
	return 2;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值