►BUDGET2...348
Программа BUDGET2 представляет собой результат преобразования программы BUDGET1, основанной на использовании функций, в объектно-ориентированную программу с применением классов.
«Для того чтобы разобраться в программе BUDGET2, вы должны быть хорошо знакомы с концепциями, представленными в третьей части книги.»
[Атас!]
В программе будет решаться задача по представлению счетов в том виде, какой они имеют в банке. Эта простая программа будет поддерживать возможности вклада ( это хорошо ) и снятия денег со счёта ( это ещё лучше ). ( Первоначальная версия работала только с одним типом банковского счёта. ) Эта версия поддерживает два типа счетов, каждый из которых будет иметь собственные, несколько отличные от другого счёта правила.
Чековый счёт:
■■■
■ удерживать 20 центов за каждый обработанный чек, если баланс падает ниже 500 долларов;
■ не удерживать 20 центов, если баланс больше 500 долларов.
■■■
Сберегательный счёт:
■■■
■ не удерживать денег при первом снятии со счёта за месяц;
■ удерживать 5 долларов за каждое последующее снятие.
■■■
Рассматривая эту задачу, можно сразу отметить, что главными кандидатами на роль классов являются Checking и Savings. Поскольку данные-члены лучше сделать защищёнными, нам понадобится несколько функций, обеспечивающих доступ к номеру и балансу счёта.
Как и любой класс, Checking и Savings нуждаются в конструкторе, чтобы проинициализировать объекты правильными значениями ( как минимум, обнулить баланс ). Кроме того, понадобятся ещё две функции — deposit( ) ( вклад ) и withdrawal( ) ( снятие ).
И наконец, в этой программе я добавил ещё одну функцию-член, которая называется display( ) ; она отображает текущий объект. Это необязательное требование, однако обычно так и поступают, позволяя объекту самому заниматься своим отображением, не полагаясь на внешнюю функцию ( которой для правильного отображения могут понадобиться сведения о внутреннем устройстве класса или другая информация, которую вы, возможно, не захотите открывать ).
Вот текст этой программы:
/* BUDGET2.CPP — программа бюджета, основанная на классах */
#include <cstdio>
#include <cstdlib>
#include <iostream>
_________________
348 стр. Часть 6. Великолепная десятка
using namespace std ;
/* Максимальное количество счетов */
const int maxAccounts = 10 ;
/* Checking — здесь описан чековый счёт */
class Checking
{
public :
Checking( int initializeAN = 0 )
:accountNumber( initializeAN ) , balance( 0.0 ){ }
/* Функции обращения */
int accountNo( )
{
return accountNumber ;
}
double acntBalance( )
{
return balance ;
}
/* Функции транзакций */
void deposit( double amount )
{
balance += amount ;
}
void withdrawal( double amount ) ;
/* Функция вывода объекта в cout */
void display( )
{
cout << "Счёт " << accountNumber
<< " = " << balance
<< " " ;
}
protected :
unsigned accountNumber ;
double balance ;
} ;
/* withdrawal — эта функция-член слишком */
/* велика для inline-функции */
void Checking::withdrawal( double amount )
{
if ( balance < amount )
{
cout << "Недостаточно денег: баланс равен "
<< balance
<< ", сумма чека равна " << amount
<< " " ;
}
else
{
balance -= amount ;
/* Если баланс падает слишком низко... */
if ( balance < 500.00 )
{
_________________
349 стр. Глава 31. Программа BUDGET
/* ...удержать деньги за обслуживание */
balance -= 0.20 ;
}
}
}
/* Savings — вы и сами можете написать этот класс */
class Savings
{
public :
Savings( int initialAN = 0 )
: accountNumber( initialAN ) ,
balance( 0.0 ) , noWithdrawals( 0 ) { }
/* функции обращения */
int accountNo( )
{
return accountNumber ;
}
double acntBalance( )
{
return balance ;
}
/* функции транзакций */
void deposit( double amount )
{
balance += amount ;
}
void withdrawal( double amount ) ;
/* Функция display — отображает объект */
void display( )
{
cout << "Счёт " << accountNumber
<< " = " << balance
<< " ( номер снятия = "
<< noWithdrawals
<< " ) " ;
}
protected :
unsigned accountNumber ;
double balance ;
int noWithdrawals ;
} ;
void Savings::withdrawal( double amount )
{
if ( balance < amount )
{
cout << "Недостаточно денег на счёте: "
<< "баланс равен " << balance
<< ", снимается " << amount
<< " " ;
}
else
{
/* После первого в месяце снятия денег... */
_________________
350 стр. Часть 6. Великолепная десятка
if ( ++noWithdrawals > 1 )
{
/* ...удерживать $5 */
balance -= 5.00 ;
}
/* Снять деньги */
balance -= amount ;
}
}
/* Объявление прототипов */
void process( Checking* pChecking ) ;
void process( Savings* pSavings ) ;
/* Объекты чековых и сберегательных счетов */
Checking* chkAcnts[ maxAccounts ] ;
Savings* svgAcnts[ maxAccounts ] ;
/* main — собирает и выводит данные */
int main( int argcs , char* pArgs[ ] )
{
setlocale ( LC_ALL , ".1251" ) ; /* печать кириллицы */
/* Повторять цикл до ввода 'X' или 'х' */
int noChkAccounts = 0 ; /* Содержит количество счетов */
int noSvgAccounts = 0 ;
char accountType ; /* Тип счёта — 'S' или 'С' */
while ( 1 )
{
cout << "Введите S для сберегательных счетов, " << " "
<< "С для чековых, "
<< "X для выхода:" ;
cin >> accountType ;
/* Выйти из цикла, если пользователь введёт X */
if ( accountType == 'x' || accountType == 'X' )
{
break ;
}
/* В противном случае обрабатывать соответствующий счёт */
switch ( accountType )
{
/* чековые счета */
case 'c' :
case 'C' :
if ( noChkAccounts < maxAccounts )
{
int acnt ;
cout << "Введите номер счёта:" ;
cin >> acnt ;
chkAcnts[ noChkAccounts ] = new Checking( acnt ) ;
process( chkAcnts[ noChkAccounts ] ) ;
noChkAccounts++ ;
}
else
{
cout << "Для чековых счетов больше нет места " ;
_________________
351 стр. Глава 31. Программа BUDGET
}
break ;
/* сберегательные счета */
case 's' :
case 'S' :
if ( noSvgAccounts < maxAccounts )
{
int acnt ;
cout << "Введите номер счёта:" ;
cin >> acnt ;
svgAcnts[ noSvgAccounts ] = new Savings( acnt ) ;
process( svgAcnts[ noSvgAccounts ] ) ;
noSvgAccounts++ ;
}
else
{
cout << "Для сберегательных счетов "
<< "больше нет места " ;
}
break ;
default :
cout << "Непонятный символ... " ;
}
}
/* А теперь показать общую сумму */
double chkTotal = 0 ;
cout << "Чековые счета: " ;
for ( int i = 0 ; i < noChkAccounts ; i++ )
{
chkAcnts[ i ] -> display( ) ;
chkTotal += chkAcnts[ i ] -> acntBalance( ) ;
}
double svgTotal = 0 ;
cout << "Сберегательные счета: " ;
for ( int j = 0 ; j < noSvgAccounts ; j++ )
{
svgAcnts[ j ] -> display( ) ;
svgTotal += svgAcnts[ j ] -> acntBalance( ) ;
}
double total = chkTotal + svgTotal ;
cout << "Сумма по чековым счетам = "
<< chkTotal
<< " " ;
cout << "Сумма по сберегательным счетам = "
<< svgTotal
<< " " ;
cout << "Общая сумма = "
<< total
<< " " ;
_________________
352 стр. Часть 6. Великолепная десятка
/* Пауза для того, чтобы посмотреть на результат работы программы */
system( "PAUSE" ) ; return 0 ;
}
/* обработка( Checking ) — ввод данных по чековым счетам */
void process( Checking* pChecking )
{
cout << "Введите положительное число для вклада, "
<< "отрицательное для снятия, 0 для завершения " ;
double transaction ;
do
{
cout << ":" ;
cin >> transaction ;
// Вклад
if ( transaction > 0 )
{
pChecking -> deposit( transaction ) ;
}
// Снятие
if ( transaction < 0 )
{
pChecking -> withdrawal( -transaction ) ;
}
} while ( transaction != 0 ) ;
}
/* обработка( Savings ) — ввод данных для сберегательных счетов */
void process( Savings* pSavings )
{
cout << "Введите положительное число для вклада, "
<< "отрицательное для снятия, 0 для завершения " ;
double transaction ;
do
{
cout << ":" ;
cin >> transaction ;
// Вклад
if ( transaction > 0 )
{
pSavings -> deposit( transaction ) ;
}
// Снятие
if ( transaction < 0 )
{
pSavings -> withdrawal( -transaction ) ;
}
} while ( transaction != 0 ) ;
}
_________________
353 стр. Глава 31. Программа BUDGET
Я запустил эту программу с приведёнными ниже данными для того, чтобы продемонстрировать, как она работает. Жирным шрифтом выделен пользовательский ввод, а обычным представлены сообщения программы.
Введите S для сберегательных счетов,
С для чековых, X для выхода:S
Введите номер счёта:123
Введите положительное число для вклада,
отрицательное для снятия, 0 для завершения
: 200
: -20
: 0
Введите S для сберегательных счетов,
С для чековых, X для выхода:S
Введите номер счёта:234
Введите положительное число для вклада,
отрицательное для снятия, 0 для завершения
: 200
: -10
: -10
: 0
Введите S для сберегательных счетов,
С для чековых, X для выхода:С
Введите номер счёта:345
Введите положительное число для вклада,
отрицательное для снятия, 0 для завершения
: 200
: -20
: 0
Введите S для сберегательных счетов,
С для чековых, X для выхода:С
Введите номер счёта:456
Введите положительное число для вклада,
отрицательное для снятия, 0 для завершения
: 600
: -20
: 0
Введите S для сберегательных счетов,
С для чековых, X для выхода:Х
Чековые счета:
Счёт 345 = 179.8
Счёт 456 = 580
Сберегательные счета:
Счёт 123 = 180 ( номер снятия = 1 )
Счёт 234 = 175 ( номер снятия = 2 )
Сумма по чековым счетам = 759.8
Сумма по сберегательным счетам = 355
Общая сумма = 1114.8
Press any key to continue...
Рассмотрим каждую из функций-членов, начиная с класса Checking. Конструктор присваивает счёту его номер. Значение по умолчанию "= 0" позволяет программе создавать объект с номером счёта по умолчанию, равным нулю.
Checking c1 = new Checking( 124 ) ;
Checking с2 = new Checking( ) ;
_________________
354 стр. Часть 6. Великолепная десятка
В данном случае объект c1 класса Checking создаётся с номером счёта, равным 123, тогда как объект с2 создаётся с номером счёта по умолчанию, который равен нулю.
Функции accountNo( ) и acntBalance( ) предоставляют внешнему миру доступ к защищённым членам accountNumber и balance. Задачей этих функций является предоставление внешним функциям — не членам значений, изменить которые невозможно. Кроме того, эти функции, обеспечивающие доступ к членам, предохраняют внешние функции от необходимости внесения изменений при переменах в методе хранения номера счёта или баланса.
Функции deposit( ) и withdrawal( ) отвечают за вложение и снятие денег со счёта. Поскольку функция deposit( ) довольно проста, она была определена как inline-функция. Функция withdrawal( ), будучи несколько сложнее, объявлена в классе, но определяется позже.
Функция display( ) выводит важные данные на устройство стандартного вывода.
Класс Savings, в сущности, идентичен классу Checking, за исключением дополнительного члена noWithdrawals, который отслеживает количество проведённых снятий.
Место под объекты сберегательного и чекового счёта выделяется в массивах svgAcnts и chkAcnts соответственно. Максимальное количество счетов определено величиной maxAccounts.
Функция main( ) несколько сложнее своей сестры из программы BUDGET1, поскольку она имеет дело с двумя разными типами счетов. После проверки ввода на равенство "X" функция main( ) использует конструкцию switch, чтобы выбрать тип счёта: С для чекового и S для сберегательного. Конструкция switch использована в этой программе по двум причинам: во-первых, её проще расширить, добавляя к ней дополнительные варианты; во-вторых, она предоставляет вариант default ( вариант по умолчанию ) для обработки неверного ввода.
Как и ранее, вторая часть функции main( ) обеспечивает отображение информации о счёте, собранной в первой части этой функции.
Обратите внимание на то, как содержимое классов Checking и Savings скрыто от main( ). Так, например, main( ) просит объект показать своё содержимое, однако при этом не имеет никакого представления о том, как класс выбирает, что именно и как это показать.
Функция process( ), которая обрабатывает текущие вложения и снятия, полагается на функции-члены deposit( ) и withdrawal( ), которые выполняют за неё всю чёрную работу. Хотя вы и знаете, как именно выполняются эти действия, помните, что process( ) об этом не имеет никакого понятия. Работа счёта касается только самого класса счёта.
Советую пройти эту программу в пошаговом режиме. Ничто иное не даст более полного представления о программе, чем её рассмотрение в действии.
Хотите — верьте, хотите — нет, но с позиции программирования BUDGET2 разрабатывается легче, чем BUDGET1. Когда я писал класс Savings, я не должен был волноваться о том, как он будет использоваться главной программой ( то же относится и к классу Checking ). Когда же я работал над функцией main( ), то не думал о содержимом класса.
Однако в этой программе есть один небольшой недостаток: классы Savings и Checking имеют очень много общего, и хотелось бы найти возможность уменьшить количество повторений кода. Эта возможность реализована в очередной версии нашей программы — BUDGET3.
Больше книг — больше знаний!
Заберите 20% скидку на все книги Литрес с нашим промокодом
ПОЛУЧИТЬ СКИДКУ