Прошу оценить код 2
Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.
Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.
Прошу поюзать и оценить код. Это продолжение моей темы http://code-live.ru/forum/cpp/285/ . Разобрал все комментарии и вот что получилось.
Защиту от дурака все таки решил сделать запросом на ввод цифр (по моему эффект получился на 95%). Единственный бок (это то, что я нашел) это ввод цифры и за ней букв, но сброс некорректного ввода не дает программе уйти в бесконечный цикл, а переходит по цифре в выбранный пункт меню либо делает расчет с этой цифрой. Приходится либо выбирать заново пункт меню, либо делать перерасчет. В принципе можно в менюшках сделать выбор не числовой, а буквенный тогда switch будет обрабатывать цифровой ввод как default... В общем ЖДУ комментарии, как всегда принимаю все камни :).
Лови кирпичи. ))
m
.main()
. Да ещё и с кривой логикой работы функции. Оно прям-таки просится на переделку.Я немножко причесал твою программу. Тоже получился не идеал, но всё же, как мне кажется, поаккуратнее.
Если ещё немножко пофантазировать на данную тему, то можно сделать класс, который содержит информацию по платежу за одну коммунальную услугу: код услуги (газ, электричество, вода), цена за единицу (цены у нас растут с удручающей регулярностью), наименование единицы измерения, расчётный месяц и год, текущее и предыдущее значения счётчика, наименование единицы измерения (возможно как код, а не строка).
При этом можно и код данной программы сделать ещё более аккуратным, и, при желании, достаточно просто будет доработать программу так, что бы она хранила на диске файл данных с предыдущими расчётами.
Здесь стопроцентный дефолт ;)))
Ты прав и по сути этот дублирующийся код можно уместить в двух функциях на проверку букв и на ввод корректных значений. Если так сделать и в функцию
double Sum_account
добавить такую красивую табличку, которая подогнана манипуляторами, то код уменьшиться раза в полтора.Для видимости переменных во всем коде я объявил свое пространство имен... ??? Если можешь объясни пожалуйста в чем подвох. Это как-то влияет на производительность?
Здесь тоже если можешь объясни. В чем проблема если три выхода? Допустим можно зациклить код в функции
Функции пытался разбить по функционалу: меню, выбор и расчет. Как можно более ограничил объявление и инициализацию переменных в функциях. Упор на расчетную часть пока не делал, так-как пытался добиться функциональности и корректного ввода пользователя.
На данном этапе осваиваю функции, до классов остался один шаг (по моей книге) так что классы для меня пока непаханая целина :)))
Спасибо, Череп, за как всегда исчерпывающие комментарии. Ответь пожалуйста на вопрос о глобальной переменной и на неоднократный выход из функции main().
TO BE CONTINUED...
Некоторые возможности C++ рекомендуется использовать только в случаях крайней необходимости: глобальные переменные, оператор
goto
, макросы (хотя это фича препроцессора...), множественное наследование и пр. В большинстве случаев это связано не с производительностью, а с качеством написания программного кода.Качественный код прост для понимания, отладки, модификации, поддержки. На начальном этапе освоения программирования эти вещи кажутся второстепенными. Но... чем дальше в лес — тем толще партизаны. Важность качества кода люди обычно начинают понимать после 30-40 часов отладки программки на полторы тысячи строк, которая почти всегда работает правильно.
Глобальные переменные плохи тем, что порождают побочные эффекты работы функций. В идеале, функция — это «чёрный ящик»: на вход подали чётко определённые данные, на выходе получили чётко определённый результат. Но если функция в результате своей работы неявно изменяет что-то вне себя (глобальные переменные), то это сразу становится потенциальным источником ошибок, которые, к тому же, достаточно трудно локализуются. А своё пространство имён, в данном случае, это даже не подстеленная соломка, а так... промокашка.
Многократные точки выхода из функции — это тоже неаккуратность, затрудняющая отладку. В идеале, опять-таки, функция должна иметь одну точку входа и одну точку выхода (в конце функции). Но лично я считаю, что функция может иметь несколько точек выхода, но только при условии строгой логической обоснованности. Например, для корректной работы функции требуется, что бы аргументы удовлетворяли определённым условиям, иначе функция будет завершаться с ошибкой. Проверки условий с выходом с ошибкой могут быть в начале функции, дабы избежать нескольких вложенных
if
'ов, но совершенно нежелательны из середины функции.В твоём случае, если брать первый вариант ф-ции
main()
, ты запутался в собственной логике работы программы. Ф-цияslct_account()
всегда заканчивает работу с кодом 0 (кстати, почему тип возвращаемого результатdouble
?). Учитывая это, и изменив условие в первомif
на обратное, получим совершенно вменяемый код:Во втором варианте, с зацикливанием, вообще ничего не получится: переменная
account
всегда будет равна 0, следовательно вторая часть условного выражения всегда false, следовательно всё выражение будет false. И вообще не понятно зачем этот цикл нужен: цикл с подобным смыслом у тебя уже реализован вslct_account()
.Резюме. Логику работы программы надо продумывать до, а не во время кодирования.
Череп, ты понимаешь, завершить программу из функции я не могу, так-как программа завершается в главном файле. Имеется две функции, в меню которых можно завершить программу, и именно они передают в
main()
true или false, ну а там где два значения там и начинается лес с партизанами:)))На счет глобальных переменных: получается получив значение
m
из функцииslct_month()
, мне нужно передавать ее по цепочке из main() вslct_account()
а изslct_account()
во все остальные.Хорошо, а если объявить переменную
m
с модификаторомstatic
? Мне же нужно чтобы она была видна во всех функциях?Я тут учитывая замечания переписал код: убрал повторы и вставил твой цикл в main(). Посмотри пожалуйста.
Спасибо за комментарии, в принципе все ясно, кроме глобальных переменных. Какая альтернатива?
Череп, просто бросилось в глаза. В году у тебя получается 13 месяцев.
и еще вот в этом куске
/*****————-КОНСТАНТЫ ————-********/
const double price1 = 0.7254; // цена на газ
const double price2 = 0.2802; // цена на воду
const double price3 = 3.41; // цена на свет
using namespace std; а тут было (my) наверно опечатка=)
Нет, это не опечатка.
но у меня на вижуале 2012 выдает там ошибку=)
Ну я не запускал тут ничего, но по замыслу автора, он, вроде, свой namespace определил и намеренно задал его по-умолчанию.
Нет, selevit, в году у меня таки 12 месяцев )) «Нулевой» месяц используется как флаг выхода. Я просто не стал кардинально менять логику работы программы.
ну я запускал все работает нормально!!!=)
Просто я программу модернизировал, в которой были определенны переменные в области видимости my, а при модернизации переменные удалил (в чем скорее всего кроется ошибка у Анонима), а директиву оставил:)
Юрий, ты смотрел мой вариант твоей программы? Я же обошёлся без глобальных переменных.
Модификатор
static
здесь не нужен. Глобальная переменная с модификаторомstatic
так и останется глобальной. Здесь вопрос чисто принципиальный: используются или не используются глобальные переменные. Чем они нехороши — я уже писал.Что можно сделать: изменить конструкцию (внутреннюю логику) программы и/или передавать информацию в функции через аргументы.
Партизаны начались даже раньше леса )) Когда программу можно завершить в нескольких местах (не вследствие ошибки, несовместимой с жизнью!), это уже указывает на недоработки в проектировании программы. Кстати о «true или false», ни одной переменной типа
bool
в программе нет ))Несколько замечаний по последней версии кода:
input_readout()
полностью унаследовала уродливость из предыдущей версии. Почему ты не стал в ней использовать ф-циюinput_choice()
? Забыл? Для ввода целых показаний счётчиков она вполне сгодится.slct_month()
иslct_account()
логичнее использовать цикл с постусловием вместо цикла с предусловием.account_menu()
,month_menu()
,Sum_account()
вообще не нужны в виде функций. Функция — это всё-таки логический блок, а не просто кусок кода. При реализации предыдущего пункта,account_menu()
иmonth_menu()
органично впишутся внутрьslct_account()
иslct_month()
соответственно.switch
вslct_month()
меня подкосил ещё в первой версии кода. Теперь он меня добил окончательно. Живучий оказался, собака ((лучше написать так:
здесь экономится пять вызовов функций
operator << ()
.