esaulenka 7 11 февраля, 2019 Опубликовано 11 февраля, 2019 · Жалоба 8 minutes ago, Nixon said: Или вы будет утверждать что никогда не возникало потребности выполнить кучу действий на этапе компиляции? Сейчас Вам в ответ дефайн на три страницы нарисуют ;-) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Nixon 4 11 февраля, 2019 Опубликовано 11 февраля, 2019 · Жалоба Не поможет. Точнее поможет только в примитивных случаях. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 18 11 февраля, 2019 Опубликовано 11 февраля, 2019 · Жалоба 4 часа назад, ViKo сказал: Я знаю, вы в C++ собаку съели, и обратно деградировать не видите смысла. Я же, действительно, не понимаю, что мне дадут классы. С целью ограничить видимость переменных должны справляться namespace. А битами порта, к примеру, я и без шаблонов манипулирую легко. Вот на C++11 и лезу. Воспользуюсь мелкими интересными свойствами. Но без ООП. Я не считаю себя крутым специалистом в C++, я просто им пользуюсь. Классы - это просто структуры с функциями. Скажем, есть у вас пакет: struct Packet { static constexpr size_t dataLength { 32 }; uint16_t header; uint16_t length; uint8_t data[dataLength]; uint16_t crc16; }; Вам нужны функции: * инициализировать пакет; * добавить байт к данным; * подсчитать CRC16; * проверить CRC16. Вы можете написать их в процедурном стиле: void packetReset(Packet* p); void packetAddData(Packet* p, uint8_t byte); uint16_t packetCalcCrc(Packet* p); , а можете добавить эти функции к классу: void Packet::reset(); void Packet::addData(uint8_t byte); uint16_t Packet::calcCrc(Packet* p); На этом этапе пока разницы между этими решениями почти никакой. Но в первом случае у нас по всей программе бегают голые, ничем не защищённые пакеты. Любая функция может поменять в пакете любое поле. В случае же с классом мы можем спрятать (инкапсулировать) данные внутри пакета. Скажем, мы можем гарантировать, что у нас число данных в буфере будет всегда строго равно значению length. Мы можем даже подсчитывать crc при каждом добавлении данных. Либо при обращении к функции Packet::getCrc() (а сам член crc16 будет приватным). Таким образом, мы очень простыми методами, без накладных расходов, увеличиваем надёжность и читаемость нашей программы. Дальше идёт полиморфизм. Это тоже удобная штука. Мы можем написать функцию, которая принимает на вход разные пакеты. И каждый пакет знает сам, как с ним работать. Но это уже тема для долгого рассказа:) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 11 февраля, 2019 Опубликовано 11 февраля, 2019 · Жалоба 5 минут назад, AHTOXA сказал: void Packet::reset(); void Packet::addData(uint8_t byte); uint16_t Packet::calcCrc(Packet* p); namespace Packet { ... } И любая функция уже не доберется. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 26 11 февраля, 2019 Опубликовано 11 февраля, 2019 · Жалоба 16 minutes ago, ViKo said: namespace Packet { ... } И любая функция уже не доберется. В с++ при вызове функции класса (метода или кто как это называет) в стек всегда кладется указатель на экземпляр класса владельца (this), который имеет доступ к этому методу и его полям (данным). В голом С это можно "эмулировать", но лицезреть подобный код - зрелище не для слабонервных :) Если же все методы класса статические (static), то класс вырождается в банальный набор голых C-функций "со всеми вытекающими". Т.е. аналог namespace - это класс с чисто статическими функциями и полями (данными). В общих чертах конечно. Короче, namespace - это НЕ аналог class, и даже близко. Хотя справедливости ради, в голом "C" namespace позволяет немного улучшить читаемость кода и поддержание в нем порядка. зы Как-то странно обсуждать такие банальные вещи аж в далеком 2019 ... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 18 11 февраля, 2019 Опубликовано 11 февраля, 2019 · Жалоба 55 минут назад, ViKo сказал: namespace Packet { ... } И любая функция уже не доберется. Почему не доберётся? Доберётся. Packet::имя_функции:) Я попробую ещё раз акцентировать мысль: Классы позволяют обеспечивать внутри себя инварианты. Данные инициализируются правильным образом в конструкторе, а функции-члены класса гарантируют инвариантность/непротиворечивость. А по-другому к членам-данным класса не обратиться. Это очень удобно, когда прочувствуешь. То есть, любая функция, которая получает указатель/ссылку на объект, не сможет неправильно прочитать его crc. Не сможет отправить некорректный/неподготовленный пакет. И так далее. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AlexandrY 3 11 февраля, 2019 Опубликовано 11 февраля, 2019 · Жалоба 4 hours ago, Forger said: У вас, как я понял, панический страх перед наличием C++ кода с ООП внутри микроконтроллера. Этот страх - ваша проблема. Эта Ваша "проблема" не имеет отношения к этой теме. Но вы правы - не буду мешать раздувать меха в старом махровый баяне в стиле "плюсы внутри МК" :) Тем не менее в моих проектах я использую классы для UART-ов - https://github.com/Indemsys/Mbed_led_blinky_MKE18F/blob/master/mbed-os/drivers/SerialBase.cpp И могу сказать по опыту, что более бессмысленного занятия чем писать такие классы трудно придумать. И кстати вы совсем не мешаете. Каждый ваш аргумент это гвоздь в С++, он становится похож на какое-то дворовое наречие или слэнг переполненный синтаксическим мусором. Переход на слэнг совсем не так безобиден. Когда мат начинают применять регулярно, то автоматически обедняется нормальный словарный запас. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 26 11 февраля, 2019 Опубликовано 11 февраля, 2019 · Жалоба 1 hour ago, AlexandrY said: более бессмысленного занятия чем писать такие классы трудно придумать. mbed - это, мягко говоря, на любителя, однако, пользуется популярностью наравне с кубами и прочей ботвой в стиле "as is" 1 hour ago, AlexandrY said: он становится похож на какое-то дворовое наречие или слэнг переполненный синтаксическим мусором. Вижу, ваша позиция осталась неизменной: "раз чего-то не понимаю, значит это - глупость" Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
k155la3 27 12 февраля, 2019 Опубликовано 12 февраля, 2019 · Жалоба On 2/10/2019 at 7:43 PM, ViKo said: Речь идет, естественно, о программе в микроконтроллере. И не о том, какие функции и буферы использовать, а какие создавать классы, и создавать ли. По словам некоторых опытных специалистов они в данном случае не нужны. Ок. Вы когда работаете в "безклассовом" режиме, все равно используете ООП, в том или ином виде. Модель-абстракция при этом хранится в голове автора. C++ позволяет "умственную" абстракцию формализировать, как минимум. При этом появляются шансы, что абстракция будет видна не только автору. С минимальными затратами времени-сил на чтение кода. Я "пользовал" ООП при работе с нескольких видов архивов во внешнем флеш (аварии, события, данные123 - 5 типов). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 12 февраля, 2019 Опубликовано 12 февраля, 2019 · Жалоба У меня есть абстракции на уровне файлов. Они будут понятны любому изучающему. Хотя, такой процедуры - передавать кому-то - не предполагаю в принципе. А теперь еще абстракции уровня namespace добавлю. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
k155la3 27 12 февраля, 2019 Опубликовано 12 февраля, 2019 · Жалоба У меня возникает иногда "проблемы" с чтением своего (!) кода 5-10 летней свежести (смех, продолжительные аплодисменты) :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 12 февраля, 2019 Опубликовано 12 февраля, 2019 · Жалоба 20 часов назад, AHTOXA сказал: а можете добавить эти функции к классу: void Packet::reset(); void Packet::addData(uint8_t byte); uint16_t Packet::calcCrc(Packet* p); А куда заносить обработчик прерывания, который пишет или читает Packet? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 178 12 февраля, 2019 Опубликовано 12 февраля, 2019 · Жалоба 57 минут назад, k155la3 сказал: У меня возникает иногда "проблемы" с чтением своего (!) кода 5-10 летней свежести (смех, продолжительные аплодисменты) :) В этом ничего плохого только в том случае, если Вы постоянно совершенствуете навыки проектирования и программирования. Я смотрю на свой код всегда критически. Даже спустя год можно найти для себя что-то новое, какой-то синтаксический сахар, который до этого момента писался в лоб и был нечитаем. А вот совсем запущенный случай, это когда всю жизнь пишешь в одном стиле, а спустя пару лет вообще не понимаешь что происходит в исходниках - это, ИМХО, результат легкомысленного отношения к ремеслу. То есть программа не продумана, возникают кучи связей, запутывание имён переменных и т.д. В этом случае нужно заняться самосовершенствованием. Ну по крайней мере я себя так успокаиваю Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 26 12 февраля, 2019 Опубликовано 12 февраля, 2019 · Жалоба 15 minutes ago, ViKo said: А куда заносить обработчик прерывания, который пишет или читает Packet? Покуда этот обработчик - обычная С-функция, "занести" куда-то его не получится. Он так и будет отдельно болтаться, даже если его вписать в какой-нить класс с припиской static. Статические методы класса (или обычные С-функции) не могут обращаться на равной к остальным методам этого же класса. Все из-за того, что при вызове подобных static методов в стек не кладется соотв. this. Решение есть, но оно не всем понравится. Вот тут посмотрите этот вариант. 5 minutes ago, Arlleex said: А вот совсем запущенный случай, это когда всю жизнь пишешь в одном стиле, а спустя пару лет вообще не понимаешь что происходит в исходниках - это, ИМХО, результат легкомысленного отношения к ремеслу. Золотые слова! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 234 12 февраля, 2019 Опубликовано 12 февраля, 2019 · Жалоба 20 часов назад, Forger сказал: В с++ при вызове функции класса (метода или кто как это называет) в стек всегда кладется указатель на экземпляр класса владельца (this), Откуда такие странные голословные утверждения??? Не знаю как насчёт "всегда", но в IAR this передаётся в регистрах. В R0 насколько помню. Да и какой смысл пихать this в стек если используется передача аргументов в регистрах? 20 часов назад, Forger сказал: зы Как-то странно обсуждать такие банальные вещи аж в далеком 2019 ... Вот именно.... 32 минуты назад, ViKo сказал: А куда заносить обработчик прерывания, который пишет или читает Packet? Читайте про static-методы. И про friend-функции. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться