Вернемся к разработке класса денег. Ранее мы реализовали простой класс, позволивший нам выполнять операции с рублями (см. главы 1 и 2). Однако практически в любой финансовой системе необходимо оперировать и другой валютой, например долларами или франками. Давайте рассмотрим мультивалютную систему, в которой используются рубли, доллары и евро. Понятно, что разные валюты обладают некоторыми общими свойствами, поэтому можно использовать механизм наследования. Однако так как мы пока не имеем опыта применения механизма наследования, нам, очевидно, наряду с разработкой классов-наследников потребуется время от времени модифицировать базовый класс.
Совершенно ясно, что арифметические операции с любой валютой — одни и те же: нам надо складывать и вычитать деньги, делить деньги на деньги, умножать и делить деньги на число. Даже операция ввода может быть унифицирована, так как практически для всех валют (по крайней мере, для долларов и евро) каждый «рубль» состоит ровно из 100 «копеек». Различия проявляются только при выводе денежной суммы на экран — необходимо указывать, в какой валюте эта денежная сумма представлена. Таким образом, мы можем реализовать базовый класс TCurrency, в котором определено поле для денежной суммы и реализованы все перечисленные операции, кроме операции вывода. Тогда конкретную валюту (рубли, доллары или евро) можно будет реализовать путем открытого наследования. Интерфейс этого класса представлен в листинге i8.1. Реализация не изменяется, за исключением названия класса, поэтому приводить мы ее не будем.
Листинг 8.1. Интерфейс базового класса TCurrency для работы с денежными суммами
class TCurrency { public:
typedef unsigned int uint;
TCurrency(const long double &t=0.0); // конструктор
// методы
TCurrency& operator+=(const TCurrency &b); TCurrency operator-() { Summa = -Summa; return *this; }; TCurrency& operator++(){ return (*this+=1.0);} TCurrency operator++(int)
{ TCurrency t = *this; *this+=0.01; return t; }
TCurrency operator-(const TCurrency &a);
TCurrency& operator-=(const TCurrency &b);
TCurrency& operator/=(const double &b);
long double operator/(const TCurrency &b);
TCurrency operator/(const double &b);
TCurrency& operator*-(const double &b);
bool isNegative() { return (Summa < 0); } // дружественные функции
friend TCurrency operator+(const TCurrency &a, const TCurrency &b);
friend TCurrency operator*(const long double &a, const TCurrency &b);
friend TCurrency operator*(const TCurrency &a, const long double &b);
friend bool operator==(const TCurrency &a, const TCurrency &b);
friend bool operator!=(const TCurrency &a,const TCurrency &b);
friend bool operator<(const TCurrency &a,const TCurrency &b);
friend bool operator>=(const TCurrency &a,const TCurrency &b);
friend bool operator>(const TCurrency &a,const TCurrency &b);
friend bool operator<=(const TCurrency &a,const TCurrency &b);
friend istream& operator>>(istream& t, TCurrency &r); private:
long double Summa;
string toStringO const;
long double round(const long double &r);
};
Разберемся, какие дополнения или изменения придется внести в классы-наследники. Во-первых, это, конечно, операция вывода на экран. При этом наша приватная функция перевода числа в символьный вид может быть реализована в базовом классе, так как она должна работать одинаково для трех валют. Напишем первый вариант наших классов-наследников (листинг 8.2).
Листинг 8.2. Классы-наследники от TCurrency // Рубли
class Roubles: public TCurrency { public:
friend ostream& operator<<(ostream& t, const Roubles &r);
};
ostream& operator<<(ostream& t, const Roubles &r)
{ string s = r.toStringO; return (t << s << "p."); }
// Доллары
class Bucks: public TCurrency { public:
friend ostream& operator<<(ostream& t, const Bucks &r);
*' продолжение &
Листинг 8.2 (продолжение)
ostream& operator<<(ostream& t, const Bucks &r)
{ string s = r.toStringO; return (t << s << "$"); }
// Евро
class Euros: public TCurrency { public:
friend ostream& operator<<(ostream& t, const Euros &r);
>:
ostream& operator<<(ostream& t, const Euros &r)
{ string s = r.toStringO: return (t << s << "evro"): }
Однако при трансляции тут же выясняется, что фуйкция toStringO недоступна в производных классах, так как в базовом классе она определена в приватной части. Поэтому необходимо создать в базовом классе секцию protected и перенести туда прототип функции toStringO:
class TCurrency { ^public:
typedef unsigned int uint:
TCurrency(const long double &t=0.0); // конструктор
// методы // . . .
// дружественные функции
// ... protected:
string toStringO const: private:
// . ..
};
Так как все три класса практически пока одинаковые, будем разбираться с нюансами открытого наследования, экспериментируя с рублями и модифицируя базовый класс, если это потребуется. |