Перейти к содержанию
    

Как делить программу на объекты?

8 minutes ago, Nixon said:

Или вы будет утверждать что никогда не возникало потребности выполнить кучу действий на этапе компиляции?

Сейчас Вам в ответ дефайн на три страницы нарисуют ;-)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 часа назад, ViKo сказал:

Я знаю, вы в C++ собаку съели, и обратно деградировать не видите смысла. Я же, действительно, не понимаю, что мне дадут классы. С целью ограничить видимость переменных должны справляться namespace. А битами порта, к примеру, я и без шаблонов манипулирую легко. :prankster2:

Вот на 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 будет приватным). Таким образом, мы очень простыми методами, без накладных расходов, увеличиваем надёжность и читаемость нашей программы.

 

Дальше идёт полиморфизм. Это тоже удобная штука. Мы можем написать функцию, которая принимает на вход разные пакеты. И каждый пакет знает сам, как с ним работать.

Но это уже тема для долгого рассказа:)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

5 минут назад, AHTOXA сказал:

void Packet::reset(); void Packet::addData(uint8_t byte); uint16_t Packet::calcCrc(Packet* p);

namespace Packet {

...

}

И любая функция уже не доберется.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

16 minutes ago, ViKo said:

namespace Packet {

...

}

И любая функция уже не доберется.

В с++ при вызове функции класса (метода или кто как это называет) в стек всегда кладется указатель на экземпляр класса владельца (this), который имеет доступ к этому методу и его полям (данным).

В голом С это можно "эмулировать", но лицезреть подобный код - зрелище не для слабонервных :)

Если же все методы класса статические (static), то класс вырождается в банальный набор голых C-функций "со всеми вытекающими". Т.е. аналог namespace - это класс с чисто статическими функциями и полями (данными). В общих чертах конечно.

Короче, namespace - это НЕ аналог class, и даже близко. Хотя справедливости ради, в голом "C" namespace позволяет немного улучшить читаемость кода и поддержание в нем порядка.

 

 

зы Как-то странно обсуждать такие банальные вещи аж в далеком 2019 ...

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

55 минут назад, ViKo сказал:

namespace Packet {

...

}

И любая функция уже не доберется.

Почему не доберётся? Доберётся. Packet::имя_функции:)

Я попробую ещё раз акцентировать мысль: Классы позволяют обеспечивать внутри себя инварианты. Данные инициализируются правильным образом в конструкторе, а функции-члены класса гарантируют инвариантность/непротиворечивость. А по-другому к членам-данным класса не обратиться. Это очень удобно, когда прочувствуешь.

То есть, любая функция, которая получает указатель/ссылку на объект, не сможет неправильно прочитать его crc. Не сможет отправить некорректный/неподготовленный пакет. И так далее.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 hours ago, Forger said:

У вас, как я понял, панический страх перед наличием C++ кода с ООП внутри микроконтроллера. Этот страх - ваша проблема. Эта Ваша "проблема" не имеет отношения к этой теме.

Но вы правы - не буду мешать раздувать меха в старом махровый баяне в стиле "плюсы внутри МК" :)

 

Тем не менее в моих проектах я использую классы для UART-ов - https://github.com/Indemsys/Mbed_led_blinky_MKE18F/blob/master/mbed-os/drivers/SerialBase.cpp
И могу сказать по опыту, что более бессмысленного занятия чем писать такие классы трудно придумать.  

И кстати вы совсем не мешаете.
Каждый ваш аргумент это гвоздь в С++, он становится похож на какое-то дворовое наречие или слэнг переполненный синтаксическим мусором.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, AlexandrY said:

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

mbed - это, мягко говоря, на любителя, однако, пользуется популярностью наравне с кубами и прочей ботвой в стиле "as is"

 

1 hour ago, AlexandrY said:

он становится похож на какое-то дворовое наречие или слэнг переполненный синтаксическим мусором.

Вижу, ваша позиция осталась неизменной: "раз чего-то не понимаю, значит это - глупость:biggrin:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 2/10/2019 at 7:43 PM, ViKo said:

Речь идет, естественно, о программе в микроконтроллере. И не о том, какие функции и буферы использовать, а какие создавать классы, и создавать ли. По словам некоторых опытных специалистов они в данном случае не нужны. Ок.

Вы когда работаете в "безклассовом" режиме, все равно используете ООП, в том или ином виде. Модель-абстракция при этом хранится в голове автора. C++ позволяет "умственную" абстракцию формализировать, как минимум. При этом появляются шансы, что абстракция будет видна не только автору. С минимальными затратами времени-сил на чтение кода. Я "пользовал" ООП при работе с нескольких видов архивов во внешнем флеш (аварии, события, данные123 - 5 типов).

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У меня есть абстракции на уровне файлов. Они будут понятны любому изучающему. Хотя, такой процедуры - передавать кому-то - не предполагаю в принципе.

А теперь еще абстракции уровня namespace добавлю. 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У меня возникает иногда "проблемы" с чтением своего (!) кода 5-10 летней свежести (смех, продолжительные аплодисменты) :)

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

20 часов назад, AHTOXA сказал:

а можете добавить эти функции к классу:


void Packet::reset();
void Packet::addData(uint8_t byte);
uint16_t Packet::calcCrc(Packet* p);

А куда заносить обработчик прерывания, который пишет или читает Packet?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

57 минут назад, k155la3 сказал:

У меня возникает иногда "проблемы" с чтением своего (!) кода 5-10 летней свежести (смех, продолжительные аплодисменты) :)

В этом ничего плохого только в том случае, если Вы постоянно совершенствуете навыки проектирования и программирования. Я смотрю на свой код всегда критически. Даже спустя год можно найти для себя что-то новое, какой-то синтаксический сахар, который до этого момента писался в лоб и был нечитаем.

А вот совсем запущенный случай, это когда всю жизнь пишешь в одном стиле, а спустя пару лет вообще не понимаешь что происходит в исходниках - это, ИМХО, результат легкомысленного отношения к ремеслу. То есть программа не продумана, возникают кучи связей, запутывание имён переменных и т.д. В этом случае нужно заняться самосовершенствованием.

Ну по крайней мере я себя так успокаиваю:blush::biggrin:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

15 minutes ago, ViKo said:

А куда заносить обработчик прерывания, который пишет или читает Packet?

Покуда этот обработчик - обычная С-функция, "занести" куда-то его не получится. Он так и будет отдельно болтаться, даже если его вписать в какой-нить класс с припиской static.

Статические методы класса (или обычные С-функции) не могут обращаться на равной к остальным методам этого же класса. Все из-за того, что при вызове подобных static методов в стек не кладется соотв. this.

Решение есть, но оно не всем понравится. Вот тут посмотрите этот вариант.

 

5 minutes ago, Arlleex said:

А вот совсем запущенный случай, это когда всю жизнь пишешь в одном стиле, а спустя пару лет вообще не понимаешь что происходит в исходниках - это, ИМХО, результат легкомысленного отношения к ремеслу.

Золотые слова! :good:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

20 часов назад, Forger сказал:

В с++ при вызове функции класса (метода или кто как это называет) в стек всегда кладется указатель на экземпляр класса владельца (this),

Откуда такие странные голословные утверждения???

Не знаю как насчёт "всегда", но в IAR this передаётся в регистрах. В R0 насколько помню. Да и какой смысл пихать this в стек если используется передача аргументов в регистрах? 

20 часов назад, Forger сказал:

зы Как-то странно обсуждать такие банальные вещи аж в далеком 2019 ...

Вот именно....  :russian_ru:

32 минуты назад, ViKo сказал:

А куда заносить обработчик прерывания, который пишет или читает Packet?

Читайте про static-методы. И про friend-функции.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...