第九章 习题答案
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;
}