Консультация № 184640
01.12.2011, 18:01
500.47 руб.
0 11 1
Уважаемые эксперты! Пожалуйста, ответьте на вопрос:
Среда - Visual Studio 2005-2007
Необходимо разработать приложение с 3 видами вкладов используя классы.
Операции для обычныго и валютного вкладов могут выполняться с частью вклада, а для срочных - только со всем вкладом.Каждый вклад реализовать своим описателем.

Описатель обычного вклада содержит: сумму вклада, дату открытия вклада и дату последней onepaции с вкладом;процент начисления по вкладу (ежемесячный, т.е. начисления на вклад выполняются, начиная от даты последнего изменения по текущую дату, которая передаётся в метод).
Описатель срочного вклада содержит: сумму вклада, дату открытия вклада и срок хранения, процент начисления по вкладу (ежемесячный).
Описатель валютного вклада содержит: название валюты, сумму вклада, дату открытия вклада и дату последней операции с вкладом, курс обмена, процент начисления по вкладу (ежемесячный, начиная от деле последней операции).

Каждый вклад имеет уникальную характеристику - номер счёта. Информация обо всех вкладах сведена в таблицу, каждый элемент которой состоит из номера счёта и указателя на описатель вклада. Элементы таблицы упорядочены по возрастанию номеров вкладов.
Функции таблицы:
включить новый элемент в таблицу, не нарушая упорядоченности;
найти элемент в таблице по номеру счёта;
исключить элемент из таблицы по номеру счёта;
показать содержимое таблицы.
Для любого вклада:
получить (вернуть в качестве результата) сумму вклада; изменить сумму вклада;
рассчитать величину начислений по процентам;
получить дату открытия вклада;
получить дату последней операции; изменить дату последней операции;
показать всю информацию о вкладе,
Для валютного вклада;
выполнить пересчёт суммы вклада в рублях
Для приложения:
открыть новый счёт;
показать текущее состояние счёта (с начислением процентов по состоянию на текущую дату);
закрыть счёт (с начислением процентов по состоянию на текущую дату);
модифицировать состояние счёта (внести деньги, снять вклад, снять проценты);
показать информацию обо всех имеющихся счётах;
выполнить пересчёт вкладов, хранящихся на всех счетах, в указанную валюту, используя класс-итератор.

Этапы выполнения
1.На основе описания задачи определить состав классов.
2.Разработать иерархию классов и схему их взаимодействия.
3.Для каждого класса определить его состояние и необходимые методы.
4.Разработать и отладить все классы. Приложение реализовать в виде простой диалоговой программы.
5.Разработать и отладить класс, реализующий работу приложения. Предусмотреть в классе возможность сохранения таблицы в файле и ее восстановления.
Опционально
Повторить разработку контейнерного класса (вместе с необходимыми итераторами), используя - стандартную библиотеку STL.
Повторить разработку контейнерного класса (вместе с необходимыми итераторами), используя собственные шаблоны классов.

Код желательно прокомментировать. Огромное спасибо за внимание!

Обсуждение

Неизвестный
10.12.2011, 13:16
общий
Добрый день! можно узнать, будет ли решение данной задачи?
давно
Посетитель
7438
7205
10.12.2011, 20:14
общий
Да, будет. Дня через два.
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
7438
7205
15.12.2011, 04:07
общий
это ответ
Здравствуйте, joker!

Вот такая получилась реализация...

vklad.cpp
[code h=207]#include "vklad.h"

void CreateVklad();
void GetVklad();
void CloseVklad();
void ModifyVklad();
void GetInfo();
void CalcUSD();
void Exit();

void PutMoney(vklad *);
void GetMoney(vklad *);
void GetPercent(vklad *);
void ChangeCourse(vklad *);
void Exit(vklad *);
int GetNum();
int ViewMenu(char**, int);

bank *b = NULL; //все счета

char * mesMain[] = //сообщения меню
{
"Открыть новый счет",
"Показать состояние счета",
"Закрыть счет",
"Изменить счет",
"Все счета",
"Пересчет всех вкладов в валюту",
"Выход"
};
//количество пунктов меню
int MesMainCount = sizeof( mesMain ) / sizeof( mesMain[0] );
//функции отработки пунктов меню
void ( *funcMain[] )()={CreateVklad, GetVklad, CloseVklad,
ModifyVklad, GetInfo, CalcUSD, Exit};

char * mesModify[] =
{
"Внести деньги",
"Снять деньги",
"Снять проценты",
"Поменять курс",
"Выход"
};
//количество пунктов меню
int MesModifyCount = sizeof( mesModify ) / sizeof( mesModify[0] );
//функции отработки пунктов меню
void ( *funcModify[] )(vklad*)={PutMoney, GetMoney, GetPercent, ChangeCourse, Exit};

void CreateVklad() //создание вклада
{
char str[64] = {0};
int num = 0;
int months = 0;
double sum = 0;
double percent = 0;
double course = 0;

if (b == NULL) //проверим наличие банка
{ //нет - создадим
cout << endl << "Создаем банк. Введите курс USD: ";
do
{
cin.getline(str, sizeof(str),'\n');
course = atof(str);
}while (str[0] == 0 || course == 0);

b = new bank(course); //создаем банк
}
else
course = b->GetCourse(); //курс берем в банке

//запросим тип счета
cout << endl << "Введите тип счета:" << endl;
v_type type = (v_type)(ViewMenu(typeStr, type_count)-1);

//номер счета
cout << "Введите номер счета: ";
do
{
str[0] = 0;
cin.getline(str, sizeof(str),'\n');
num = atol(str);
}while (str[0] == 0 || num == 0);

//сумма
cout << "Введите сумму: ";
do
{
str[0] = 0;
cin.getline(str, sizeof(str),'\n');
sum = atof(str);
}while (str[0] == 0 || sum == 0);

//процент
cout << "Введите процент: ";
do
{
str[0] = 0;
cin.getline(str, sizeof(str),'\n');
percent = atof(str);
}while (str[0] == 0 || percent == 0);

switch (type)
{
case normal:
b->Add(new Normal(sum, percent), num);
break;
case monetary:
b->Add(new Monetary(sum, percent, course), num);
break;
case forward:
//заносим число месяцев
cout << "Введите срок хранения (в месяцах): ";
do
{
str[0] = 0;
cin.getline(str, sizeof(str),'\n');
months = atol(str);
}while (str[0] == 0 || months == 0);
b->Add(new Forward(sum, percent, months), num);
}
}

void GetVklad()
{
char str[64] = {0};
int num = 0;
vklad *vkl;
//номер счета
cout << "Введите номер счета: ";
do
{
str[0] = 0;
cin.getline(str, sizeof(str),'\n');
num = atol(str);
}while (str[0] == 0 || num == 0);
vkl = b->GetVklad(num);
if (vkl)
{
vkl->handle->CalcVklad(vkl->handle->GetCurrentDate());
vkl->handle->View();
}
else
cout << "Такого счета нет" << endl;
}

void CloseVklad()
{
char str[64] = {0};
int num = 0;
vklad *vkl;

cout << "Введите номер счета: ";
do
{
str[0] = 0;
cin.getline(str, sizeof(str),'\n');
num = atol(str);
}while (str[0] == 0 || num == 0);
vkl = b->GetVklad(num);
if (vkl)
{
vkl->handle->Close(vkl->handle->GetCurrentDate());
}
else
cout << "Такого счета нет" << endl;
}

void ModifyVklad()
{
char str[64] = {0};
int ret, num = 0;
vklad *vkl;

cout << endl << "Введите номер счета: ";
do
{
str[0] = 0;
cin.getline(str, sizeof(str),'\n');
num = atol(str);
}while (str[0] == 0 || num == 0);
vkl = b->GetVklad(num);
if (vkl)
{
if (vkl->handle->IsOpen())
{
do
{
ret = ViewMenu(mesModify, MesModifyCount);
funcModify[ret-1](vkl);
if (ret == MesModifyCount)
break;
cout << endl;
}while ( ret );
}
else
cout << "Счет закрыт" << endl;
}
else
cout << "Такого счета нет" << endl;
}

void PutMoney(vklad *vkl)
{
try
{
char str[64] = {0};
double sum = 0;

if (vkl->handle->GetType() == forward)
throw "На срочный вклад нельзя вносить деньги";
if (!vkl->handle->IsOpen())
throw "На закрытый счет нельзя внести деньги";
vkl->handle->CalcVklad(vkl->handle->GetCurrentDate());
cout << endl << "Введите сумму: ";
do
{
str[0] = 0;
cin.getline(str, sizeof(str),'\n');
sum = atof(str);
}while (str[0] == 0 || sum == 0);
vkl->handle->SetSum(vkl->handle->GetSum() + sum);
}
catch(char * str)
{
cout << str << endl;
}
}

void GetMoney(vklad *vkl)
{
try
{
char str[64] = {0};
double sum = 0;
double sum_vklad;

vkl->handle->CalcVklad(vkl->handle->GetCurrentDate());
sum_vklad = vkl->handle->GetSum();

if ((vkl->handle->GetType() == forward) && vkl->handle->IsOpen())
throw "C открытого срочного вклада нельзя снять деньги";

cout << "Введите сумму, которую хотите снять: ";
do
{
str[0] = 0;
cin.getline(str, sizeof(str),'\n');
sum = atof(str);
}while (str[0] == 0 || sum == 0);

if ((vkl->handle->GetType() == forward) && (sum_vklad != sum))
throw "Cо срочного вклада можно снять только все деньги сразу";
if (sum > sum_vklad)
throw "Денег на счету меньше, чем Вы хотите снять";
sum_vklad -= sum;
vkl->handle->SetSum(sum_vklad);
cout << "Получите " << sum;
if (vkl->handle->GetType() == monetary)
cout << " " << ((Monetary*)vkl->handle)->GetCurrency();
else
cout << " RUR";
cout << endl;
}
catch(char * str)
{
cout << str << endl;
}
}

void GetPercent(vklad *vkl)
{
try
{
char str[64] = {0};
double sum;
double sum_vklad;

if (!vkl->handle->IsOpen())
throw "C закрытого вклада нельзя снять проценты";

vkl->handle->CalcVklad(vkl->handle->GetCurrentDate());

sum_vklad = vkl->handle->GetSum();

sum = vkl->handle->GetSumPercent();

vkl->handle->SetSum(sum_vklad - sum);
cout << "Получите " << sum;
if (vkl->handle->GetType() == monetary)
cout << " " << ((Monetary*)vkl->handle)->GetCurrency();
else
cout << " RUR";
cout << endl;
}
catch(char * str)
{
cout << str << endl;
}
}

void ChangeCourse(vklad *vkl)
{
double course = 0;
char str[64] = {0};

cout << "Введите курс USD: ";
do
{
cin.getline(str, sizeof(str),'\n');
course = atof(str);
}while (str[0] == 0 || course == 0);

b->SetCourse(course);
}

void Exit(vklad *vkl){}

//вывод информации о счетах
void GetInfo()
{
try
{
if (b)
b->View();
else
throw "Сначала откройте счет!";
}
catch(char * str)
{
cout << str << endl;
}
}

void CalcUSD()
{
vklad * vkl;

cout << "Пересчёт вкладов, хранящихся на всех счетах, в USD:" << endl;
for (vkl=b->first(); vkl!=NULL; vkl=b->next())
{
vkl->handle->CalcVklad(vkl->handle->GetLastDate());
if (vkl->handle->GetType() == monetary)
cout << "Счет №" << vkl->num << ":\t" <<
vkl->handle->GetSum() << " " << ((Monetary*)vkl->handle)->GetCurrency() << endl;
else
cout << "Счет №" << vkl->num << ":\t" <<
(double)((int)((vkl->handle->GetSum()/b->GetCourse())*100)/100) << " USD" << endl;
}
}

void Exit(){}

int GetNum()
{
int a;
cin >> a;
while ( !( cin.good() || cin.eof() ) || ( a < 0 ) )
{
cout << "Введите число! " << endl;
cin.clear();
cin.ignore();
cin >> a;
}
return a;
}

int ViewMenu(char** mes, int max)
{
int ret;
do
{
for ( int i = 0; i < max; i++ )
cout << i+1 << ". " << mes[i] << endl;
cout << "Ваш выбор: ";
ret = GetNum();
}
while ( ret < 1 || ret > max );
return ret;
}

int main()
{
setlocale(LC_ALL,"Russian");

int ret;
do
{
ret = ViewMenu(mesMain, MesMainCount);
funcMain[ret-1]();
cout << endl;
if (ret == MesMainCount)
break;
}while ( ret );

delete b;
system("pause");
return 0;
}

[/code]
vklad.h
[code h=207]#include <windows.h>
#include <locale>
#include <iostream>
#include <list>
#include <string.h>

using namespace std;

//тип вклада
enum v_type
{
normal,
monetary,
forward,
type_count
};

char *typeStr[type_count] =
{
"обычный",
"валютный",
"срочный"
};

struct VDATE
{
unsigned char day;
unsigned char month;
unsigned short year;
};

class Normal
{
private:
v_type _Type;
double _Sum;
double _SumFirst;
VDATE *_CreateDate;
VDATE *_LastDate;
double _Percent;
bool _open;
public:
Normal(double sum, double percent, v_type type=normal)
{
_Type = type;
_Sum = sum;
_SumFirst = sum;
_CreateDate = GetCurrentDate();
_LastDate = GetCurrentDate();
_Percent = percent;
_open = true;
}
~Normal()
{
delete _CreateDate;
delete _LastDate;
}

friend class Monetary;

inline v_type GetType(){return _Type;}
inline double GetSum(){return _Sum;}
inline double GetSumPercent(){return (_Sum-_SumFirst);}
inline void SetSum(double sum){_Sum = sum;}
inline VDATE* GetCreateDate(){return _CreateDate;}
inline VDATE* GetLastDate(){return _LastDate;}
inline void SetLastDate(VDATE *date){*_LastDate = *date;}
inline double GetPercent(){return _Percent;}
inline bool IsOpen(){return _open;}
virtual void Close(VDATE *pdate)
{
if (_open)
{
CalcVklad(pdate);
_open = false;
}
}
VDATE* GetCurrentDate()
{
SYSTEMTIME st;
VDATE *dt = new VDATE;
GetLocalTime(&st);
dt->day = (unsigned char)st.wDay;
dt->month = (unsigned char)st.wMonth;
dt->year = (unsigned short)st.wYear;
return dt;
}
virtual void CalcVklad(VDATE *pdate)
{
try
{
int days = pdate->day - _LastDate->day;
int months = pdate->month - _LastDate->month;
int years = pdate->year - _LastDate->year;

if (!IsOpen())
throw "Для закрытого счета рассчитать величину начислений невозможно";

if (days < 0)
{
days += 30;
months--;
}
if (months < 0)
{
months += 12;
years--;
}
if (years < 0)
throw "Неверно задана дата";

_Sum += _Sum * (((years*12 + months) + ((double)days)/30)) * _Percent / 100;
_Sum = ((double)((int)(_Sum * 100)))/100;
SetLastDate(pdate);
}
catch(char * str)
{
cout << str << endl;
}
}

bool SetClose(Normal * v);

virtual void View()
{
char str[32];

cout << endl << "Счет\t\t";
if (_open)
cout << "открыт";
else
cout << "закрыт";
cout << endl << "Тип вклада:\t" << typeStr[_Type] << endl;
cout << "Сумма:\t\t" << _Sum << endl;
sprintf(str, "%02d.%02d.%04d", _CreateDate->day, _CreateDate->month, _CreateDate->year);
cout << "Дата создания:\t" << str << endl;
sprintf(str, "%02d.%02d.%04d", _LastDate->day, _LastDate->month, _LastDate->year);
cout << "Дата изменения:\t" << str << endl;
sprintf(str, "%5.2f%%", _Percent);
cout << "Процент:\t" << str << endl;
};
};

class Monetary: public Normal
{
private:
char *_Currency;
double _Course;
public:
Monetary(double sum, double percent, double course, char *currency = "USD")
:Normal(sum, percent, monetary)
{
if (currency)
{
_Currency = new char[strlen(currency)+1];
strcpy(_Currency, currency);
}
_Course = course;
}
~Monetary(){delete _Currency;}
virtual void View()
{
char str[32];

Normal::View();
cout << "Валюта:\t\t" << _Currency << endl;
sprintf(str, "%5.2f", _Course);
cout << "Курс:\t\t" << str << endl;
cout << "Сумма в рублях:\t" << GetRub() << endl;
};
inline double GetRub(){return GetSum() * _Course;}
inline void SetCourse(double c){_Course = c;}
inline char * GetCurrency(){return _Currency;}
};

class Forward: public Normal
{
private:
int _MonthCount;
int _MonthBalance;
public:
Forward(double sum, double percent, int months)
:Normal(sum, percent, forward)
{
_MonthCount = months;
_MonthBalance = months;
}
virtual void CalcVklad(VDATE *pdate)
{
try
{
VDATE *last = GetLastDate();
int days = pdate->day - last->day;
int months = pdate->month - last->month;
int years = pdate->year - last->year;

if (!IsOpen())
throw "Для закрытого счета рассчитать величину начислений невозможно";

if (days < 0)
{
days += 30;
months--;
}
if (months < 0)
{
months += 12;
years--;
}
if (years < 0)
throw "Неверно задана дата";

int monthcount = (years*12 + months) + (days/30) ;
if (monthcount)
{
if (monthcount > _MonthBalance)
monthcount = _MonthBalance;
int sum = GetSum();
sum += sum * monthcount * GetPercent() / 100;
sum = ((double)((int)(sum * 100)))/100;
SetSum(sum);

_MonthBalance -= monthcount;
last->month += monthcount;
while (last->month > 12)
{
last->month -= 12;
last->year++;
}
SetLastDate(last);
SetClose(this);
}
}
catch(char * str)
{
cout << str << endl;
}
}
inline int GetTail(){return _MonthBalance;}
virtual void Close(VDATE *pdate)
{
if (IsOpen())
CalcVklad(pdate);
}
virtual void View()
{
Normal::View();
cout << "Срок хранения:\t" << _MonthCount << " мес" << endl;
};
};

bool Normal::SetClose(Normal * v)
{
if (v->GetType() == forward && ((Forward*)v)->GetTail() == 0)
{
_open = false;
return true;
}
return false;
}

struct vklad
{
int num;
Normal *handle;
};

class bank //класс банка
{
private:
double _course;
list <vklad*> table; //таблица вкладов
list <vklad*>::iterator it; //итератор для работы со списком
public:
bank(double course=0){_course = course;}
~bank()
{
for(it=table.begin(); table.size(); it=table.begin())
{
delete (*it)->handle;
table.erase(it);
}
}
bool Add(Normal * vkl, int n) //добавление
{
int i;

//ищем, куда ставить, чтобы было отсортировано (сортировка вставкой)
//по всем вкладам
for(it=table.begin(); it!=table.end(); it++)
{
//сравним номера счетов
i = (*it)->num - n;
if (i == 0) //равны - такой уже есть. Предполагаем, что все разные
return FALSE;
else if (i > 0) //больше - сюда вставляем
break;
} //или в конец списка

vklad * v = new vklad;
v->num = n;
v->handle = vkl;
table.insert(it, v); //вставляем в таблицу
return TRUE; //отработали
}
bool Del(int n) //удаление
{
int i;

//ищем по всем вкладам
for(it=table.begin(); it!=table.end(); it++)
{
//сравним номера счетов
i = (*it)->num - n;
if (i == 0)
{
delete (*it)->handle;
table.erase(it);
return true;
}
else if (i > 0) //больше - сюда вставляем
break;
}
return false;
}
void SetCourse(double course)
{
_course = course;
for(it=table.begin(); it!=table.end(); it++)
{
if ((*it)->handle->GetType() == monetary)
((Monetary*)((*it)->handle))->SetCourse(course);
}
}

inline double GetCourse(){return _course;}

vklad * GetVklad(int n)
{
int i;

for(it=table.begin(); it!=table.end(); it++)
{
i = (*it)->num - n;
if (i == 0)
return (*it); //равно - наш вклад
else if (i > 0)
break;
}
return NULL; //0 - не нашли
}
//показ всей инфы по всем вкладам
void View()
{
cout << endl << "Таблица вкладов" << endl;
cout << "Всего: " << table.size() << endl;
//вывод инфы о каждом вкладе
for(it=table.begin(); it!=table.end(); it++)
{
cout << endl << "Номер счета: " << (*it)->num << endl;
(*it)->handle->View();
}
}

vklad * first()
{
it = table.begin();
if (it != table.end())
return (*it);
else
return NULL;
}
vklad * next()
{
it++;
if (it != table.end())
return (*it);
else
return NULL;
}
};
[/code]
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
давно
Посетитель
7438
7205
15.12.2011, 04:08
общий
Комментарии добавлю чуть позже.
Пока попробуйте разобраться самостоятельно.
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
15.12.2011, 14:17
общий
Адресаты:
Спасибо за помощь! Пока возникла проблема с компиляцией.

forward: неоднозначный символ
может быть v_type forward
или c:\program files (x86)\microsoft visual studio 10.0\vc\include\utility(77) : _Ty &&std::forward(identity<_Ty>::type &)"

Я понимаю что используется v_type forward

И еще вопрос, _sum используется только для хранение суммы умноженной на проценты?
давно
Посетитель
7438
7205
15.12.2011, 15:18
общий
Да, имеется в виду v_type forward
_sum - текущие денюжки
проценты учитываются при расчете, как _sum = _sum + _sum * procents
И опять в _sum текущий вклад
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
15.12.2011, 15:36
общий
15.12.2011, 15:55
Адресаты:
А вы не подскажите как корректно решить проблему с "forward: неоднозначный символ"? Пока я только вспомнил через отдельное пространство имен, вида Vklad::forward
Я не нашел по коду реализации 5.Разработать и отладить класс, реализующий работу приложения. Предусмотреть в классе возможность сохранения таблицы в файле и ее восстановления.
А в целом реализация
давно
Посетитель
7438
7205
15.12.2011, 15:45
общий
Похоже, совпало имя. Попробуйте переименовать везде в программе forward на, например, forwd
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
15.12.2011, 20:18
общий
Я днем не заметил, в vklad.h используется STL list необходима основная программа без использования файла шаблонов. И выше написал про загрузку/выгрузку таблицы из файла.
давно
Посетитель
7438
7205
15.12.2011, 20:25
общий
Ок, подправлю...
Об авторе:
"Если вы заметили, что вы на стороне большинства, —
это верный признак того, что пора меняться." Марк Твен
Неизвестный
15.12.2011, 20:43
общий
И можете не тратить время на комментарии, код записан замечательно!

Если будут вопросы по методам лучше тут спрошу. Еще раз спасибо!
Форма ответа