![]() |
Модераторы: bsa |
![]() ![]() ![]() |
|
Zakary |
|
||||
Шустрый ![]() Профиль Группа: Участник Сообщений: 59 Регистрация: 3.5.2006 Репутация: нет Всего: нет |
здраствуйте
![]() есть сейчас программа....использует наследование. (наследование это называется?) надо сделать так чтобы использовала полиморфизм. надо сделать вектор поинтеров к объектам класса checkingAccount и savingsaccount. разрешите указать кол-во денег чтобы снять со счета используя debit(), или положить используя credit(). определите тип счета. (определить тип - как? использовать надо typeid? по другому можно? как используется typeid?) а по другому можно? если счет savings - посчитать процент используя функцию calculateInterest. если счет checking - если транзакция успешная, то снять деньги за транзакцию. все коды есть....надо только сделать теперь это с помощью полиморфизма. неважно pure virtual это или просто virtual. чистая виртуальная функция называется?. класс абстрактный получается. вообще в россии обычно используют checkingAccounts. можно расплачиваться в магазине и т.д...а savings просто сберегательный, деньги только в банкомате снять можно.... ![]() вектор поинтеров легко сделать.
вот мой код. нет как таковой функции main ещё. просто проблема в том что я не знаю куда что переносить и делать virtual. про полиморфизм читал-читал...а тут непонятно как делать:
|
||||
|
|||||
Rififi |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1254 Регистрация: 9.3.2008 Репутация: 3 Всего: 36 |
Zakary,
фига себе улыбочка... тут животик надорвать можно (: полиморфизм у тебя работать не будет. он предполагает наличие виртуальных функций в классе, коих не наблюдается. определите тип счета. (определить тип - как? использовать надо typeid? по другому можно? как используется typeid?) а по другому можно? никакой typeid использовать не надо. в классе должна быть виртуальная функция которая возвращает тип
в наследниках переопределяешь GetType, возвращаешь нужный тип. всё. с остальными функциями аналогично. |
|||
|
||||
Zakary |
|
|||
Шустрый ![]() Профиль Группа: Участник Сообщений: 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. значит надо в двух наследниках засовывать эти функции. ЧТО буду возвращать эти функции? и КАК ![]() ![]() |
|||
|
||||
mes |
|
|||
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 79 Всего: 250 |
в том варианте, что предложил Riffi, с каждым типом у Вас должно быть проассоцированно целое число, которое и будет возвращать упомянутая функция объекта каждого типа. И по значению этого числа Вы сможете косвенно определить какого типа у Вас объект. Однако этот вариант оставляет желать лучшего, так как для операций с объектом придется делать динамическое приведение типа. Но объяснять Вам более сложною, но надежную конструкцию, ИМХО, будет смысл только после того как разберетесж с основами ![]() |
|||
|
||||
Zakary |
|
|||
Шустрый ![]() Профиль Группа: Участник Сообщений: 59 Регистрация: 3.5.2006 Репутация: нет Всего: нет |
а мне кажется можно и объяснить, а?
![]() ну пожалуйста.... будет мне очень полезно....хотя бы вкратце ![]() |
|||
|
||||
mes |
|
|||
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 79 Всего: 250 |
||||
|
||||
fry |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 257 Регистрация: 4.10.2006 Репутация: 2 Всего: 3 |
Zakary, используй dynamic_cast. Для его использования необходимо, чтобы твои классы содержали виртуальную функцию (можешь читать как полиморфизм). используя его с указателем на интерфейсный класс (суперкласс с перечислением твоих методов в виде чисто виртуальных функций, это с "...=0") ты можешь узнать конкретный тип. Конкретный вариант исполнения можешь прогуглить (ИМХО долго искать не придется).
|
|||
|
||||
sdukshis |
|
|||
Шустрый ![]() Профиль Группа: Участник Сообщений: 92 Регистрация: 23.3.2009 Репутация: нет Всего: 1 |
В этой задаче действительно лучше использовать динамический полиморфиз.
Если вкратце то идея такая: У вас есть базовый класс с методами debit() и credit() И есть его наследники, которые определяют собственные реализации этих методов. Далее нужно хранить набор указателей на эти классы. Поскольку хранить в контейнерах можно, только однотипные данные, то храниться будут указатели на базовый класс. Главное, что бы при вызове методов вызывались именно для данного типа счета. Все это позволяет реализовать динамический полиморфизм на основе виртуальных функций. Синтаксис примерно следующий
|
|||
|
||||
Zakary |
|
|||
Шустрый ![]() Профиль Группа: Участник Сообщений: 59 Регистрация: 3.5.2006 Репутация: нет Всего: нет |
а как мне в таком коде вызывать функции с дочернего класса. что-то типа v[1]->setInterestRate не рабоатет ведь =\
а в конструкторах дочерних инициализация такая и останется разве? :Account(b)? |
|||
|
||||
mes |
|
|||
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 79 Всего: 250 |
потому что операция не полиморфна. есть три (как минимум) варианта решения Вашей задачи (вызова 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б. |
|||
|
||||
toxx |
|
||||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 653 Регистрация: 4.3.2009 Где: НН Репутация: 4 Всего: 13 |
fry dynamic_cast используется если программа не продумана тут вродебы можно вполне обойтись одними указателями и полиморфизм будет.
Потом если косвенно обращаться к методам... вобщем всё окей будет. |
||||
|
|||||
mes |
|
|||
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 79 Всего: 250 |
||||
|
||||
toxx |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 653 Регистрация: 4.3.2009 Где: НН Репутация: 4 Всего: 13 |
mes
Имел ввиду без dynamic_cast лучше делать. |
|||
|
||||
mes |
|
|||
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 79 Всего: 250 |
без него конечно лучше, но мне что то подсказывает. что автор выберет именно этот вариант, так как остальное требует больших затрат. Буду рад, если ошибся ![]() |
|||
|
||||
toxx |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 653 Регистрация: 4.3.2009 Где: НН Репутация: 4 Всего: 13 |
Когда мне требовался полиморфизм, я без dynamic_cast обошелся...Да и тут вродебы все не на столько сложно чтоб указателями пользоваться.Вобщем выбор за автором, но советую пользоваться указателями. |
|||
|
||||
fry |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 257 Регистрация: 4.10.2006 Репутация: 2 Всего: 3 |
Я думаю это личное дело каждого пользоваться динамическим приведением или нет(ИМХО вариант с числовыми константами мне вообще не нравится, как мне кажется он подвержен ошибкам не менее других способов). Однако думается для конечной реализации автору темы стоит выбрать тот вариант, который он более всего понимает и соответственно в котором менее всего возможны ошибки при реализации. В данном случае визитор работает на более высоком "уровне понимания" и реализация его может занять больше усилий. Стоит принять во внимание дальнейшее использование данной схемы автором. Если это всего навсего решение одной задачи, то динамическое приведение будет лучшим вариантом. Если автор будет использовать ее и далее, то лучше конечно визитор.
PS Интересно, с чего это динамическое приведение свидетельствует о непродуманности. Оно проверяет корректность приведения в ходе выполнения и используется как раз в таких случаях. В плане статического я еще могу согласиться (ИМХО не всегда). Это сообщение отредактировал(а) fry - 27.4.2009, 00:22 |
|||
|
||||
mes |
|
|||
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 79 Всего: 250 |
Потому что подвержена ошибкам, в частности возможно (в лестнице условий) 1. вместо приведения к внуку приведется к сыну (при неправильной очередности лестницы условий) 2. забыто применение операции к какому либо типу , особенно при позднем (после ) измении иерархии и т.д Визитор лишен этого, так создает законченную матрицу вызовов, но это же является и недостатком, так как для закончености требуется, чтоб были известны все типы и также обладает излишиством, так как у каждой добавляемой операции должна быть реализация пусть хоть пустая, но требующая времени программиста. Но если применение визитора выбрано правильно применительно к задаче, то его преимущества с лихвой окупают недостатки. |
|||
|
||||
fry |
|
||||||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 257 Регистрация: 4.10.2006 Репутация: 2 Всего: 3 |
toxx:
fry:
mes:
Конечно подвержено, однако это не свидетельствует о непродуманности. Во всяком случае четко сказать, что код с dynamic_cast непродуман нельзя. В целом все кодирование подвержено ошибкам (ИМХО люди все же) - что-то больше (dynamic_cast), что-то меньше, однако если руки не из того места или нет опыта и понимания можно любую хорошую (визитор) идею изгадить. |
||||||
|
|||||||
mes |
|
||||||
любитель ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7954 Регистрация: 14.1.2006 Репутация: 79 Всего: 250 |
О "не продуманности" свидетельствует то, что взят первый попавшийся, а не максимально подходящий, способ. Сам динамик_кaст тут не при чем. Зависит как он применен. К примеру лестница условий, в которой по очереди идет преобразование к потомку, с окончанием при успешном приведении. Так еще такое для каждой операции (функции) этой иерархии.
Одно дело изгадить, а другое что контроль, который можно было повесить на компилятор, приходится делать вручную. И (не для учебного проекта из 1000 строк) это довольно трудоемкий процесс. Особенно если над проектом работает не один, а группа. |
||||||
|
|||||||
fry |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 257 Регистрация: 4.10.2006 Репутация: 2 Всего: 3 |
Согласен со всем. Предложил этот метод потому, что:
1. это, как я понял, как раз и есть "проект из 1000 строк" 2. это просто для понимания 3. ИМХО лучше варианта с константами |
|||
|
||||
![]() ![]() ![]() |
Правила форума "C/C++: Для новичков" | |
|
Запрещается! 1. Публиковать ссылки на вскрытые компоненты 2. Обсуждать взлом компонентов и делиться вскрытыми компонентами
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa. |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | C/C++: Для новичков | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |