Модераторы: bsa

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> полиморфизм с улыбкой... переделываем из наследования.. 
:(
    Опции темы
Zakary
Дата 25.4.2009, 07:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 59
Регистрация: 3.5.2006

Репутация: нет
Всего: нет



здраствуйте smile

есть сейчас программа....использует наследование. (наследование это называется?)
надо сделать так чтобы использовала полиморфизм.
надо сделать вектор поинтеров к объектам класса checkingAccount и savingsaccount.
разрешите указать кол-во денег чтобы снять со счета используя debit(), или положить используя credit().
определите тип счета. (определить тип - как? использовать надо typeid? по другому можно? как используется typeid?)  а по другому можно?
если счет savings - посчитать процент используя функцию calculateInterest.
если счет checking - если транзакция успешная, то снять деньги за транзакцию. все коды есть....надо только сделать теперь это с помощью полиморфизма. неважно pure virtual это или просто virtual. чистая виртуальная функция называется?. класс абстрактный получается.

вообще в россии обычно используют checkingAccounts. можно расплачиваться в магазине и т.д...а savings просто сберегательный, деньги только в банкомате снять можно.... smile так на всякий случай.

вектор поинтеров легко сделать. 
Код

vector <Account *> accounts(2);
accounts[0]=new CheckingAccount(......)
.......


вот мой код. нет как таковой функции main ещё. просто проблема в том что я не знаю куда что переносить и делать virtual. про полиморфизм читал-читал...а тут непонятно как делать:
Код

account.h
#ifndef ACCOUNT_H
#define ACCOUNT_H
#include<iostream>
using namespace std;

class Account
{
public:
    Account(double);
    void setBalance(double);
    double getBalance();
    void credit(double);
    bool debit(double);
    void printBalance();

private:
    double balance;
};
#endif

checkingAccount.h
#ifndef CHECKINGACCOUNT_H
#define CHECKINGACCOUNT_H
#include<iostream>
#include"q3.pseew.account.h"
using namespace std;

class CheckingAccount: public Account
{
public:
    CheckingAccount(double, double);
    void setTransactionFee(double);
    double getTransactionFee();
    void credit(double);
    bool debit(double);
    
private:
    double transactionFee;
        void chargeFee();
};

#endif

SavingsAccount.h
#ifndef SAVINGSACCOUNT_H
#define SAVINGSACCOUNT_H
#include<iostream>
#include "q3.pseew.account.h"
using namespace std;

class SavingsAccount: public Account
{
public:
    SavingsAccount(double, double);
    void setInterestRate(double);
    double getInterestRate();
    double calculateInterest();

private:
    double interestRate;
};
#endif

account.cpp
#include<iostream>
#include<iomanip>
#include"q3.pseew.account.h"
using namespace std;

Account::Account(double b)
{
    setBalance(b);
}
void Account::setBalance(double b)
{    
    if(b < 0.0)
    {
        b = 0.0;
        cout << "Initial balance was invalid, the balance is now set to $0.00" << endl;
    }
    else
        balance = b;
}
double Account::getBalance()
{
    return balance;
}
void Account::credit(double credit)
{
    balance = balance + credit;
}
bool Account::debit(double debit)
{
    if(debit > balance)
    {
        cout << "Debit ammount exceeded account balance" ;
        return false;
    }
    else
    {    
        balance = balance - debit;
        return true;
    }
}
void Account::printBalance()
{
    cout << fixed << '$' << setprecision(2) << getBalance() << endl;
}

checkingaccount.cpp
#include<iostream>
#include"q3.pseew.checkingaccount.h"
using namespace std;
CheckingAccount::CheckingAccount(double b, double f)
:Account(b)
{
    setTransactionFee(f);
}
void CheckingAccount::setTransactionFee(double f)
{
     if (f >=0.0)
    transactionFee = f;
     else
        transactionFee= 0.0;
}
double CheckingAccount::getTransactionFee()
{
    return transactionFee;
}
void CheckingAccount::credit(double amount)
{
     Account::credit(amount);
     chargeFee();
}
bool CheckingAccount::debit(double amount)
{
        bool success = Account::debit(amount);
        if (success)
        {    
            chargeFee();
        return true;
        }
        else
            return false;
}
void CheckingAccount::chargeFee()

     Account::setBalance(getBalance()-getTransactionFee());
     cout<< "$"<<transactionFee << "transaction fee charged." <<endl;
}

savingsaccount.cpp

#include<iostream>
#include "q3.pseew.savingsaccount.h"
using namespace std;

SavingsAccount::SavingsAccount(double b, double r)
: Account(b)
{
    setInterestRate(r);
}
void SavingsAccount::setInterestRate(double r)
{
        if (r>=0.0)
      interestRate = r;
        else
          interestRate=0.0;
}
double SavingsAccount::getInterestRate()
{
    return interestRate;
}
double SavingsAccount::calculateInterest()
{
    return  getInterestRate() * getBalance();
}



PM MAIL   Вверх
Rififi
Дата 25.4.2009, 08:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1254
Регистрация: 9.3.2008

Репутация: 3
Всего: 36



Zakary
фига себе улыбочка... тут животик надорвать можно (:
полиморфизм у тебя работать не будет. он предполагает наличие виртуальных функций в классе, коих не наблюдается.

определите тип счета. (определить тип - как? использовать надо typeid? по другому можно? как используется typeid?)  а по другому можно?
никакой typeid использовать не надо.
в классе должна быть виртуальная функция которая возвращает тип
Код
enum AccountType
{
    ...
};

class Account
{
public:
    virtual ~Account() {}
    virtual AccountType GetType() = 0;
};


в наследниках переопределяешь GetType, возвращаешь нужный тип. всё. с остальными функциями аналогично.
PM MAIL   Вверх
Zakary
Дата 25.4.2009, 21:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 59
Регистрация: 3.5.2006

Репутация: нет
Всего: нет



class Account
{
public:
    Account(double);
    void setBalance(double);
    double getBalance();
   virtual void credit(double);
    virtual bool debit(double);
    void printBalance();
private:
    double balance;
};

я ставлю virtual на 2 функции credit and debit.
в одном наследнике эти функции изменены чуть. 
во втором классе они берутся из главного класса. 
вопрос: "Можно ли мне вызывать функцию credit и debit для savingsAccount не писав эти функции в savigns?" или надо virtual тоже?
дальше. 
 virtual AccountType GetType() = 0; это pure virtual. 
значит надо в двух наследниках засовывать эти функции. ЧТО буду возвращать эти функции? и КАКsmile я вообще не понимаюsmile как они return сделают что это SavingsAccount?



PM MAIL   Вверх
mes
Дата 25.4.2009, 21:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 79
Всего: 250



Цитата(Zakary @  25.4.2009,  20:45 Найти цитируемый пост)
ЧТО буду возвращать эти функции? и КАКsmile я вообще не понимаюsmile как они return сделают что это SavingsAccount?

в том варианте, что предложил Riffi, с каждым типом у Вас должно быть проассоцированно целое число, которое и будет возвращать упомянутая функция объекта каждого типа.
И по значению этого числа Вы сможете косвенно  определить какого типа у Вас объект. Однако этот вариант оставляет желать лучшего, так как для операций с объектом придется делать динамическое приведение типа. Но объяснять Вам более сложною, но надежную конструкцию, ИМХО, будет смысл только после того как разберетесж с основами smile



--------------------
PM MAIL WWW   Вверх
Zakary
Дата 25.4.2009, 22:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 59
Регистрация: 3.5.2006

Репутация: нет
Всего: нет



а мне кажется можно и объяснить, а?smile
ну пожалуйста....
будет мне очень полезно....хотя бы вкратце smile
PM MAIL   Вверх
mes
Дата 25.4.2009, 23:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 79
Всего: 250





--------------------
PM MAIL WWW   Вверх
fry
Дата 25.4.2009, 23:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 257
Регистрация: 4.10.2006

Репутация: 2
Всего: 3



Zakary, используй dynamic_cast. Для его использования необходимо, чтобы твои классы содержали виртуальную функцию (можешь читать как полиморфизм). используя его с указателем на интерфейсный класс (суперкласс с перечислением твоих методов в виде чисто виртуальных функций, это с "...=0") ты можешь узнать конкретный тип. Конкретный вариант исполнения можешь прогуглить (ИМХО долго искать не придется).
PM MAIL   Вверх
sdukshis
Дата 25.4.2009, 23:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 92
Регистрация: 23.3.2009

Репутация: нет
Всего: 1



В этой задаче действительно лучше использовать динамический полиморфиз.

Если  вкратце то идея такая:
У вас есть базовый класс с методами debit() и credit()
И есть его наследники, которые определяют собственные реализации этих методов.

Далее нужно хранить набор указателей на эти классы.
Поскольку хранить в контейнерах можно, только однотипные данные, то храниться будут указатели на базовый класс.

Главное, что бы при вызове методов вызывались именно для данного типа счета.

Все это позволяет реализовать динамический полиморфизм на основе виртуальных функций.

Синтаксис примерно следующий
Код

class Account {
//...
public:
virtual void credit(double)= 0; 
};

class CheckingAccount:public Account{
//...
public:
virtual void credit(double d){   //Важно, чтобы сигнатура совпадала с предком
//Реализация CheckingAccount::credit
}
};
class SavingAccount:public Account{
//...
public:
virtual void credit(double d){
//Реализация SavingAccount::credit
}
};

//...

vector<Account*> v(2);
v[0]=new CheckingAccount;
v[1]=new SavingAcount;

v[0]->credit(d); //Вызывается  CheckingAccount::credit
v[1]->credit(d); //Вызывается  SavingAccount::credit



PM MAIL   Вверх
Zakary
Дата 26.4.2009, 02:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 59
Регистрация: 3.5.2006

Репутация: нет
Всего: нет



а как мне в таком коде вызывать функции с дочернего класса. что-то типа v[1]->setInterestRate не рабоатет ведь =\

а в конструкторах дочерних инициализация такая и останется разве? :Account(b)?
PM MAIL   Вверх
mes
Дата 26.4.2009, 11:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 79
Всего: 250



Цитата(Zakary @  26.4.2009,  01:09 Найти цитируемый пост)
а как мне в таком коде вызывать функции с дочернего класса. что-то типа v[1]->setInterestRate не рабоатет ведь =\

потому что операция не полиморфна.
есть три (как минимум) варианта решения Вашей задачи (вызова setInterestRate текущего объекта, зная только указатель на базовый класс)
1 Сделать эту функцию в базовом классе,
  а. и результатом возвращать успешность применения операции к объекту текущего класса (т.е если текущий объект типа checking, то ф-ция ничего не сделает и вернет false)
  б. также ничего не делает, но для проверки можно ли применить эту операцию к текущему объекту сделать еще одну дополнительную ф-цию
      например HaveSetIntererestRate.
2.a. Каждому типу присвоить целое значение, например 1 для checking и 2 для saving. Возвращать это значение посредством виртуальной функции базового класса  getType ()
    и через switch в зависимости от возвращаеммого значения посредством dynamic_cast получать  указательтекуего типа объекта.
    т.е примерно так switch (pBase->getType())
                                   {
                                      eChecking : ..
                                      eSaving : { pSavingAccount * p = dynamic_cast<pSavingAccount*>(pBase); p->SetInterestRate (..); break; }
                                  } 
   б. делать сразу динамик_каст и если не нуль то значит объект нужного типа и применять  к нему операцию.
       if (pSavingAccount * p = dynamic_cast<pSavingAccount*>(pBase))  p->SetInterestRate (..);
3. использовать паттерн визитор, пример по ссылке двумя постами выше.

3й - самый безопасный вариант, наиболее подходит для вашего случая, но требует усилий и понимания основ.
у двух остальных много слабых мест, но для простых задачек подойдут.
Если двойного наследования не предвидится (наследование от детей), то на текущем этапе знаний легче всего будет применить 2б.

 




--------------------
PM MAIL WWW   Вверх
toxx
Дата 26.4.2009, 12:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 653
Регистрация: 4.3.2009
Где: НН

Репутация: 4
Всего: 13



Цитата(fry @ 25.4.2009,  23:11)
Zakary, используй dynamic_cast. Для его использования необходимо, чтобы твои классы содержали виртуальную функцию (можешь читать как полиморфизм). используя его с указателем на интерфейсный класс (суперкласс с перечислением твоих методов в виде чисто виртуальных функций, это с "...=0") ты можешь узнать конкретный тип. Конкретный вариант исполнения можешь прогуглить (ИМХО долго искать не придется).

fry
dynamic_cast используется если программа не продумана тут вродебы можно вполне обойтись одними указателями и полиморфизм будет.

Код

Account* p;
.....

p=new CheckingAccount;
....
p=new SavingAccount;



Потом если косвенно обращаться к методам... вобщем всё окей будет.
PM MAIL   Вверх
mes
Дата 26.4.2009, 12:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 79
Всего: 250



Цитата(toxx @  26.4.2009,  11:30 Найти цитируемый пост)
тут вродебы можно вполне обойтись одними указателями и полиморфизм будет.


Цитата(Zakary @  26.4.2009,  01:09 Найти цитируемый пост)
а как мне в таком коде вызывать функции с дочернего класса. что-то типа v[1]->setInterestRate не рабоатет ведь =\

?


--------------------
PM MAIL WWW   Вверх
toxx
Дата 26.4.2009, 16:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 653
Регистрация: 4.3.2009
Где: НН

Репутация: 4
Всего: 13



mes
Имел ввиду без dynamic_cast лучше делать.
PM MAIL   Вверх
mes
Дата 26.4.2009, 18:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 79
Всего: 250



Цитата(toxx @  26.4.2009,  15:08 Найти цитируемый пост)
Имел ввиду без dynamic_cast лучше делать. 

без него конечно лучше, но мне что то подсказывает. что автор выберет именно этот вариант,
так как остальное требует больших затрат. Буду рад, если ошибся smile



--------------------
PM MAIL WWW   Вверх
toxx
Дата 26.4.2009, 19:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 653
Регистрация: 4.3.2009
Где: НН

Репутация: 4
Всего: 13



Цитата(mes @ 26.4.2009,  18:58)
Цитата(toxx @  26.4.2009,  15:08 Найти цитируемый пост)
Имел ввиду без dynamic_cast лучше делать. 

без него конечно лучше, но мне что то подсказывает. что автор выберет именно этот вариант,
так как остальное требует больших затрат. Буду рад, если ошибся smile

Когда мне требовался полиморфизм, я без dynamic_cast обошелся...Да и тут вродебы все не на столько сложно чтоб указателями пользоваться.Вобщем выбор за автором, но советую пользоваться указателями.
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Для новичков"
JackYF
bsa

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.1424 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.