Классовая борьба
- Войдите на сайт для отправки комментариев
Товарищи по несчастью (обдурине и нечестному Си), помогите, пожалуйста, привести мысль в порядок.
Есть у меня потребность сгруппировать несколько объектов в одну структуру, чтобы не придумывать кучу уникальных имен для глобальных переменных (объекты живут постоянно и взаимосвязаны: например объект EthernetServer, несколько внешних по отношению к нему метрик). Я сделал это, естественно под влиянием дурмана, через класс. Всё в принципе работает, но внутренний голос не дает жить - давай, говорит, делай покрасивше, поправильней и поэкономней по ресурсам - может namespace всобачишь или еще какие извращения применишь... Читал про использование класса без создания экземпляра. Но так, как сам не мест... сторонник функционального программирования, то оценить в перспективе ценность выделки такой овчинки затрудняюсь.
Отсюда вопрос: какую стратегию стоит рассмотреть для группировки глобальных объектов с прицелом в экономию ресурса МК (RAM/Progmem)?
А я думал квон новую ветку про классы открыл :(
///какую стратегию стоит рассмотреть для группировки глобальных объектов с прицелом в экономию ресурса МК (RAM/Progmem)?
Работает - не трогай.
Без экземпляра только статический класс. И функции по максимуму inline и const
Ежели нравится функциональное программирование, то namespace - вполне себе решение. А вообще - настолько ли жмут ресурсы, что классы вызывают стойкое отторжение? Там же много вкусного из паттернов можно применить, тот же singleton и пр. и пр. - за это вполне себе можно заплатить лишними несколькими байтами.
Не пойми неправильно: 21-й век на дворе, восьмибитки скоро отомрут, в нормальных МК щас памяти - тоже норм: та же blue pill c STM на борту, или SAMD21.
И вообще: у мну когнитивный диссонанс - поднят вопрос об оптимальном подходе при работе с ресурсами МК, в контексте нещадного оверхеда, который приносит тудыть Wiring. А вот если выкинуть нахер Wiring и, по старинке, ручонками - то можно смело юзать классы и не морщить лоб: ресурсов, освобождённых отказом от Wiring - хватит с головой, да ещё и останется.
Давно уже считаю так: экономить нужно разумно. И если нигде не жмёт - нехрен рефлексировать. А сразу закладываться на идеального сферического коня в вакууме - да не бывает так, обязательно заказчик чего-нибудь выдумает/передумает/дополнит/пр.
З.Ы. Пишу всё классами, активно юзаю String, виртуальные методы - никто пока от этого не умер.
Зато у тебя все лишнее для других будет в классе спрятано. Я тоже активный классоюзер.
Никакого отторжения нет. Я не занимаюсь программированием профессионально, не сильно знаком с трендами, тенденциями и паттернами, а так же их сильными и слабыми сторонами. Мог выбрать во всех аспектах проигрышный вариант. Поэтому обратился за советом - на что стоит обратить внимание, чтобы не усугублять ситуацию с Вайрингом. А ручонками... можно и так, только не окупаются затраты времени/нервов. Ищу что-то среднее - чтобы вышло не совсем тупо, но и красноглазить не начинать.
З.Ы. Пишу всё классами, активно юзаю String, виртуальные методы - никто пока от этого не умер.
+100500. Я ещё и delay не стесняюсь использовать.
З.Ы. Пишу всё классами, активно юзаю String, виртуальные методы - никто пока от этого не умер.
+100500. Я ещё и delay не стесняюсь использовать.
И я. И в Секте Свидетелей Переполнения Миллис не состою.
+100500. Я ещё и delay не стесняюсь использовать.
Да Вы небось ещё и GOTO используете? :-)
Когда надо - ни минуты ни в чём не сомневаясь.
Ооооо. РЕНЕГАТЫ. На костер, на костер!!!!!!!
Право мастера - осознанно нарушать правила и общепринятые нормы.
Право мастера - осознанно нарушать правила и общепринятые нормы.
Придуманные придурками в институте :(
ЗЫ. Не мастер, но delay и goto использую.
Странно это.
Я вот уже около четверти века не использую GOTO. Совсем.
И еще ни разу не понадобилось.
Странно это.
Я вот уже около четверти века не использую GOTO. Совсем.
И еще ни разу не понадобилось.
Ни разу не использовал с момента начала занятий программированием. Ни разу не понадобилось :)
Странно это.
Я вот уже около четверти века не использую GOTO. Совсем.
И еще ни разу не понадобилось.
Ни разу не использовал с момента начала занятий программированием. Ни разу не понадобилось :)
При изучении Си тяжко было обходиться без GOTO. После Бейсика и Фортрана. Но когда разобрался - все хорошо и без него получается.
А насчет delay - процессору же надо чем то заниматься когда нечего делать. :-))))
Да все, кто отписался, что не использует goto - ещё как используют, просто в неявном виде. Каждый if, switch/case, return - это всё goto (jz je jmp). Исказили, блин, высказывание старичка, он не говорил, что goto никогда нельзя использовать, он говорил, что программу с обилием goto намного сложнее отлаживать и поддерживать, и с этим я полностью согласен.
Да все, кто отписался, что не использует goto - ещё как используют, просто в неявном виде. Каждый if, switch/case, return - это всё goto (jz je jmp).
if switch - это обусловленный логикой переход, а goto - произвольный. Для меня goto в программе - как признак отсуствия логичного мышления у автора. За все годы программирования goto не использовал ни разу... и рука не тянется.
Против String у меня такого предубеждения нет... но все равно не использую. Тут причина в другом - я начинал учить Си на системе, где ничего подобного не было, поэтому использование char* для меня привычнее и проще.
Для меня goto в программе - как признак отсуствия логичного мышления у автора.
Ну я всегда знал, что интеллектом не блещу, но видимо на старости лет и логику пропил. Ибо использую goto иногда, чтоб сделать аналог блока try catch throw.
Не боись, дед, я с тобой не блещу. Не вижу, например, смысла, в наслоении if-ов и мегабайтов скобок вместо того, чтобы выскочить с goto при таймауте интерфейса, например, откуда-нибудь из глубин процедуры к ее концу, произвести финализирующие действия и сделать единый return.
Коллеги, ни в коем случае не хотел обидеть - в высказывании об отсуствии логики имел в виду себя лично :)
Правильно читать так - "если мне пришлось использовать ГОТО - значит логика программы плохая". А говоря короче - западло :)
Так, собака ж понятно, где зарыта. Вот внимательно сравните две фразы:
"За все годы программирования goto не использовал ни разу"
"String ... начинал учить Си на системе, где ничего подобного не было"
Т.е. человек начинал на языке, в котором можно обойтись без goto (поскольку, если бы начинал с Фортрана или там с Ассемблера, или даже, как я, с восьмеричных кодов, то куда бы, нафиг, делся!).
Также и про стринг: начинал там где не их было, привык обходиться и сейчас не испытывает потребности.
Так что, ребята, те кто начинал с языков, где без goto можно обойтись, просто не имеют навыков его использования - вы просто "не умеете их готовить" :)))))
--------
Кстати, надеюсь, никто не оспаривает авторитет Дональда Кнута в программировании, и не отказывает ему в наличии логики? У него есть большая статья об использовании goto, кому интересно почитайте. Общий вывод таков (стр. 22, прав. колонка, второй абзац сверху):
«Использование ругательств, таких как goto, иногда может быть уместно даже в самом приличном обществе» (Д. Кнут)
(примечание: я перевёл выражение «four-letter words» («четырехбуквенные слова») как «ругательства», т.к. смысл этого выражения в точности соответствует русскому «трёхбуквенные слова», но называть goto трёхбуквенным словом было бы как-то нелогично).
«Использование ругательств, таких как goto, иногда может быть уместно даже в самом приличном обществе» (Д. Кнут)
очень хорошая аналогия! С таким подходом вполне согласен. Воспитанный человек не сыплет трехбуквенными словами направо и налево, а использует их в тех (весьма редких) ситуациях. где они вполне к месту :)
Так что, ребята, те кто начинал с языков, где без goto можно обойтись, просто не имеют навыков его использования - вы просто "не умеете их готовить" :)))))
Полностью поддерживаю. Фортран, который мне преподавали состоял из goto чуть более чем полностью. Оттуда же пошла привычка, что переменные, имена которых начинаются с I-N - целого типа, просто на автомате.
for i=... пошло ведь оттудова, никто почему-то до сих пор не пишет for a=...
Поэтому, к goto отношусь без всякой предвзятости. Можно обойтись и без него, но зачем, правда, как sadman сказал, вертеть кружева логики, если посреди тела функции произошла ошибка? Можно просто уйти на метку err: восстановить чо надо и уйти красиво.
но зачем, правда, как sadman сказал, вертеть кружева логики, если посреди тела функции произошла ошибка? Можно просто уйти на метку err: восстановить чо надо и уйти красиво.
Деда, для этого чеканутые гики придумали декомпозицию ;) Если у тебя кружева логики сильно закружены - декомпозиция спасает, и потребность "уйти на метку err:" убывает в геометрической прогрессии ;)
Я в этих ваших лжывых плюсах не силён. Даже понятия не имею про декомпозицию.
правила и общепринятые нормы.
да, ладно Вам! Кто сказал, что неиспользование goto - правило и общепринятая норма? Профессионалы используют там где это нужно безо всяких проблем. Хотите пруф? Их есть у меня - наш коллега wdrcula как-то не поленился нарыть - http://arduino.ru/forum/programmirovanie/arduino-i-shablon-template-typename-t#comment-283850
Я в этих ваших лжывых плюсах не силён. Даже понятия не имею про декомпозицию.
Деда, не пались: декомпозиция существует для всего, а не только для нечистых плюсов :)
Ну вот настолько я непроходимо туп. Ну не программист я, увы. :( мошт, чо найду, почитаю.
а пошто у уважаемых коллег ассемблерный JMP/JZ/JNC и т.д не вызывают идиосинкразию?
а пошто у уважаемых коллег ассемблерный JMP/JZ/JNC и т.д не вызывают идиосинкразию?
Они их не видят в IDE ;)
идиосинкразию?
Неприличными словами не выражацца!
У меня, помница, наоборот, недоумение вызвала ассемблерная инструкция BNV мотороловского 6800, которая гласит Branch never, то бишь "Не переходить никогда". Я помница, аж в ступор впал, для чего нужна такая инструкция. Теперь в мануалах она стыдливо обозвана как NOP, но находится, тем не менее, в группе "Переходы и вызовы подпрограмм".
Чёта Вы напутали дед! В мотороле такой штуки я не встречал, а вот в других местах эта BNV встречается нередко (например, TMS320F, семейство FR от FUJITSU, и т.д.) и везде это "перейти, если не было переполнения").
Евгений, не надо ломиться в открытую дверь. Мы на одной стороне )
Я имел ввиду ровно то же самое, но не конкретно про goto, а про все мифы и легенды, о которых шла речь.
Средство языка, которое не дозволено новичку, дозволено профессионалу, ибо он знает, что это такое, каковы последствия, и умеет готовить. Сравните с рыбой фугу, например.
Что же касается несчастного goto, слишком много чести - из-за него копья ломать. Старик Кнут уже давно всё объяснил.
ЗЫ. На моём опыте на миллион строк кода приходится один оператор goto. Но это именно там, где он уместен и даже код читабельней. А с появлением возможности бросать исключения даже редкая необходимость goto в структурных языках резко уменьшилась.
Ностальгия нахлынула? )
Тема про классы, господа.
Мне непонятно, откуда пошло мнение, что классы жрут ресурсы? Какие именно ресурсы, не хотите ли разобраться?
Если речь о динамической памяти, но никто вас насильно не заставляет создавать экземпляры в куче. Это должно быть обусловлено исключительно требованиями задачи, а не потому, что так было в примерах, по которым вы изучали язык. В скетчах для ардуино редко нужно динамически распределять память. Набор аппаратных средств, а с ними и программных объектов статичен. В моей практике все экземпляры классов оказываются статичны, и нет необходимости в динамике.
Что ещё? Таблица виртуальных методов? Но она размещается в программной памяти, в ОЗУ ей делать нечего, и существует в одном экземпляре на каждый класс (тип). А если нет виртуальных методов у класса, то нет и VMT.
Кстати, класс без виртуальных методов и с одной только секцией public становится полностью аналогичен структуре (struct). А это уже не так страшно, правда? ) Немногие новички знают, что структуры в плюсах могут иметь методы и поддерживают наследование - замечательные такие простые классы, да?!
Евгений, не надо ломиться в открытую дверь. Мы на одной стороне )
Сам вижу, что на одной стороне, никто никуда не ломится. Беседуем, на то и форум, чтоб общаться, а не как некоторые "навички" думают - чтобы им "памагать" и "сопли подтирать" :))))
«Ох, не надо бы вслух, ох, не надо бы» (А. Галич)
Щас набигут и начнут корованы грабить :(
А с виртуальными методами, что, не становится?
Прошу ...
struct Kaka { Kaka(const int n) { m_n = n; } virtual void print(void) { Serial.println(m_n); } int m_n; }; struct KakaHex : public Kaka { KakaHex(const int n) : Kaka(n) {} void print(void) { Serial.println(m_n, HEX); } }; void setup(void) { Serial.begin(57600); Kaka k1(240); KakaHex k2(240); k1.print(); k2.print(); } void loop(void) {}Всё работает как и ожидалось.
UPDATE: я тут пока чай пил подумал, чтобы уж совсем не оставалось сомнений, что это честно работающая виртуальность (а заодно, чтобы показать её мощь), функцию setup в примере лучше заменить на такую, которая глубже задействует механизмы виртуальности:
struct Kaka { Kaka(const int n) { m_n = n; } virtual void print(void) { Serial.println(m_n); } int m_n; }; struct KakaHex : public Kaka { KakaHex(const int n) : Kaka(n) {} void print(void) { Serial.println(m_n, HEX); } }; void setup(void) { Serial.begin(57600); Kaka k1(240); KakaHex k2(240); // Kaka * ptr = & k1; ptr->print(); ptr = & k2; ptr->print(); } void loop(void) {}Результат, разумеется не изменился.
Чёта Вы напутали дед! В мотороле такой штуки я не встречал, а вот в других местах эта BNV встречается нередко (например, TMS320F, семейство FR от FUJITSU, и т.д.) и везде это "перейти, если не было переполнения").
да, естесственно я все перепутал. И моторола была 6809 и инструкция звалась BRN. Но, тем не менее. :)
ну, там она, говорят, случайно получилась :) Там во внутреннем представлении, у всех команд перехода была маска - при каких флагах команда переходит. Ну, вот при всех 0-лях получилась BRN (никогда не переходить), а при всех 1-цах получилась обратная ей BRA (безусловный переход). Никто эту BRN особо не планировал, но раз уж получилась :)
Мне непонятно, откуда пошло мнение, что классы жрут ресурсы? Какие именно ресурсы, не хотите ли разобраться? Если речь о динамической памяти, но никто вас насильно не заставляет создавать экземпляры в куче.
Когда пишешь раз в пятилетку на Big PC - об этом как-то не думаешь. А если еще и на скриптовых языках - то такие вопросы впринципе в голову не приходят.
А тут вот есть интерес в 2кб упихаться по максимуму - поэтому и возникают нездоровые мысли об оптимизации. Но все попробовать - жизни не хватит. Отсюда и вопрос: выбор класса, как некоего враппера - это выбор нормальный или есть получше?
Задача у меня, конечно, позаковыристей: есть два драйвера, немного отличаются методами. Надо было сделать так, чтобы из основного кода дергать всё однотипно и держать некоторое кол-во метрик . Вот я и того... через условную компиляцию два варианта класса завел и по нужде один из них прикомпиливаю.
Отсюда и вопрос: выбор класса, как некоего враппера - это выбор нормальный или есть получше?
Задача у меня, конечно, позаковыристей: есть два драйвера, немного отличаются методами. Надо было сделать так, чтобы из основного кода дергать всё однотипно и держать некоторое кол-во метрик . Вот я и того... через условную компиляцию два варианта класса завел и по нужде один из них прикомпиливаю.
1. Самое то!
2. Не обязательно условную компиляцию, можно интерфейсы, типа такого:
// Hardware Abstraction Layer interface struct HALDriver { virtual void InitDriver() = 0; virtual void WriteToDriver() = 0; .... }; // Implementation class Driver1 : public HALDriver { public: Driver1() {}; virtual void InitDriver() { Serial.println("Init driver #1"); } virtual void WriteToDriver() { Serial.println("Write to driver #1"); } }; class Driver2 : public HALDriver { public: Driver2() {}; virtual void InitDriver() { Serial.println("Init driver #2"); } virtual void WriteToDriver() { Serial.println("Write to driver #2"); } }; Driver1 drv1; void setup() { Serial.begin(9600); Driver2* drv2 = new Driver2(); HALDriver* ptr = &drv1; ptr->InitDriver(); ptr->WriteToDriver(); ptr = drv2; ptr->InitDriver(); ptr->WriteToDriver(); delete drv2; } void loop() { }Обращения - однотипны, через интерфейс. Можно держать и глобальные объекты, и на куче создавать, когда надо. Каждый наследник HALDriver реализует работу со своей железкой, наружу выставляя только определённый набор методов. Можно на лету переключаться между драйверами, руля разными железками на одной плате - совершенно однотипно.
Во-во. Это и есть следующая ступенька развития построения программ с помощью классов после "традиционого qwone-кода". И если бы DIYMan забивал форум такими скетчами, то пинали уже его, а не меня.
ПС: Там этих ступенек еще вагон и маленькая тележка.
И если бы DIYMan забивал форум такими скетчами, то пинали уже его, а не меня.
Нам тебя хватает :)
Прошу прощения, ошибался. Откуда я это взял, не припомню. Наверное, сам додумал ;)
Действительно, классы и структуры в C++ отличается уровнем доступа по-умолчаню, и больше ничем. Всё, что можно делать с классами, можно и со структурами.
Для любителей искать оверхед замечу, что есть различие в занимаемой памяти для структур (классов) с виртуальными методами и без оных. При наличии виртуальных методов структура должна содержать (невидимую для программиста) ссылку на VMT. Вот на размер этого указателя каждый экземпляр будет кушать больше памяти. Об этом знает только компилятор, sizeof() должен показать тот же размер. Последнее утверждение я не проверял, но думаю, что так должгно быть.
Ответ простой: "не мона, а нуна" )
По мере роста сложности программы растёт необходимость в иерархическом её построении. А ООП - прекрасное средство поддержки иерархических структур. Поэтому продумывайте и создавайте ваши структуры данных в виде классов - и будет вам счастье.
Большая система, в принципе не жизнеспособна, если не построена на основе иерархии.
Живой пример: операционная система - это иерархия абстракций.
DIYMAN, просвети, реально в С++ можно наследовать класс от структуры?
"Для любителей искать оверхед замечу, что есть различие в занимаемой памяти для структур (классов) с виртуальными методами и без оных. При наличии виртуальных методов структура должна содержать (невидимую для программиста) ссылку на VMT. Вот на размер этого указателя каждый экземпляр будет кушать больше памяти."
Не только. Сама VMT в гарвардской архитектуре лежит в SRAM и занимает место. Уже несколько лет назад к разработчикам GCC обращались подправить, дабы VMT оставалась в PROGMEM но .. как понимаю "воз и ныне там".
Отсюда оверхед не только на тайный указатель, но и на количество виртуальных методов у класса.
Тем не менее, и даже без плюсов виртуальные callback-и делаются не так уж и сложно:
/** * Проверяет заданный буфер на совпадение с шаблоном, * в случае расхождения вызывает callback() и возвращает 1 * прерывает работу, если callback() возвращает не 0. * * @param void (*)callback(uint16_t _addr, uint8_t _pattern, uint8_t _readed) * @return count summary errors */ uint16_t emsMemtest( uint8_t * _buffer, // буфер поиска расхождения uint16_t _size, // размер буфера uint8_t _pattern, // искомый образец uint8_t (*callback)(uint8_t *_addr, uint8_t _pattern, uint8_t _readed) // нашел тут это! ){ uint16_t res = 0; do{ uint8_t tmp = *_buffer; if( tmp != _pattern ){ if( callback(_buffer, _pattern, tmp) ) return res; res++; } _buffer++; }while( _size-- > 0 ); return res; }Функция проверки расширенной SRAM при обнаружении ошибки вызывает callback-параметр и по его результату принимает решение продолжить или завершиться. Как-то так.. не помню, из рабочей это версии или из предварительной.
В целом, в Си-шную структуру такие указатели на функции впендюриваются "на раз" и в общем-то необходимость в виртуальных методах отпадает или становится не значительной. А без виртуальности С++, как ЕвгенийП уже замечал ранее - это "Си с классами", которые .. ага, по компактности кода практически равны "С со структурами". :)
Откуда я это взял, не припомню.
С union перепутал. Это те - как раз класссы, но без виртуальности.
Действительно, классы и структуры в C++ отличается уровнем доступа по-умолчаню, и больше ничем. Всё, что можно делать с классами, можно и со структурами.
Если быть до конца точным, то и то, и другое - классы, просто немного разные разновидности. В С++ есть три ключевых слова с помощью которых создаётся класс: class, union и struct. Это прямо (именно в такой формулировке) записано в стандарте языка.
DIYMAN, просвети, реально в С++ можно наследовать класс от структуры?
Конечно. И наоборот - тоже. И то, и другое - классы.
Для проверки, в моём последнем скетче в строке 7 замените struct на class, а после этой строки добавьте public: и убедитесь.
спасибо, не знал. В Delphi такова нет.