К вопросу о титановых велосипедах и программировании вообще

GarryC
Offline
Зарегистрирован: 08.08.2016

"Перед нами только что предстала возможность провести небольшие и крайне интересные тактические учения".

Просматривал свои реплики на форуме и наткнулся на совершенно невнятное "О, Господи!" в ветке о "титановом велосипеде", которая была вызвана знакомством с предлагаемым автором кодом. К сожалению, я тогда не раскрыл свою позицию, прошло 2 года и многие читатели этого форума успели ознакомиться с вышеуказанным кодом и некоторые даже сообщили автору, что "У вас очень крутой код:)".

Признаю, это моя вина, и, возможно, эти люди уже потеряны для программирования, но лучше поздно, чем никогда. Поэтому предлагаю Вашему вниманию мои заметки по поводу того, как следовало бы решать данную задачу (по моему мнению) и в чем лично я вижу недостатки представленного автором упомянутого поста решения.
Примечание: поскольку я не понял, как делать черновики постов на данном сайте, я буду выкладывать очередные части (да, их будет более, чем одна) в виде комментариев к данному начальному посту. Если кто знает более правильный способ, сообщите в комментариях или в личку (хотя ее я тоже не вижу).

Итак, мы начинаем.

Прежде всего ряд общих соображений, независимо от конкретной проблемы. Мы собираемся создавать "библиотеку", то есть программный модуль, отчуждаемый от автора, который будет эксплуатироваться третьими лицами без контакта с создателем данного модуля. Здесь уместно переиначить известное изречение "Как следуем писать программы для других? Так же, как и для себя, но намного лучше."
То есть мы должны уделить особое внимание вопросам простоты использования кода, понятности кода, документирования кода - всему тому, что при программировании "для себя" обычно уходит на второй план.
Ну и, конечно, правильность работы кода является непременным условием создания программы вообще, если есть ограничения на возможность использования кода, они должны быть явным способом прописаны либо в тексте, либо в документации.

А теперь перейдем к конкретной задаче и начнем ее решать, исходя их только что приведенных принципов.

Разрабатываем библиотеку для работы с временными интервалами. Сама по себе задача не сложная и решена не один раз, обычно используется код типа следующего:

unsigned long delay1 = millis(); //момент начала отсчета 
...
if ((millis()- delay1) > time1) {DoSomething();}; // если время истекло, то делаем нечто

К сожалению, данное простое и абсолютное верное решение не отвечает одному из принципов программирования, а именно: делает не то, что пользователю (в денном случае программисту прикладной задачи) нужно, а то, что оно умеет. В данном случае мы хотели бы ожидать наступления некоторого интервала после некоторого момента времени, а не присваивать каким-то переменным непонятные значения и проводить с ними загадочные операции, смысл которых пользователю не до конца ясен (всех заинтересовавшихся отсылаю к посту http://arduino.ru/forum/programmirovanie/velikoe-perepolnenie-millis, хотя, по моему мнению, (горизонт завален) тема до конца не раскрыта, ведь далеко не все, Евгений, смогут прочитать и, главное, понять, без-знаковую арифметику).  Поэтому вполне естественно стремления спрятать от пользователя внутреннюю кухню, чем и занимается предложенный код. Каким образом мы можем достичь требуемого результата?

Способ 1 - МАКРОС. Несмотря на имеющее место глубокое предубеждение против данного способа, он вполне себе действенен, а иногда и едва ли не единственен, если речь идет о С. Примечание: я тоже не очень макросы в С люблю, но совсем по иной причине, нежели большинство - я просто работал с действительно настоящими языками пре-процессинга и поэтому аналогичное по функциям решение в С у меня вызывает жалость и недоумение, но продолжим.
Как может выглядеть решение на макросах:

# define DelayStart(Delay) unsigned long Delay = millis()
# define DelayIsOver(Delay,Time) ((millis()- Delay) > (Time))
и соответствующий фрагмент кода перепишем как:
DelayStart(delay1);
...
if (DelayIsOver(delay1,time1) {DoSomething();};

Решение вполне рабочее, хотя и далеко не идеальное, рекомендовать его я не буду, просто надо было же с чего-то начинать.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Подпишусь.

GarryC
Offline
Зарегистрирован: 08.08.2016

Решение номер 1 можно (и должно) улучшать, но лучше с ним покончить и перейти к
Способ 2 - переменные и функции, в котором предлагается следующий набор сущностей:

typedef unsigned long DelayType;
DelayType DelayStart(void) { return millis(); };
int DelayIsOver(DelayType Delay,unsigned int Time) return ((millis() - Delay) > Time)

DelayType delay1;
delay1=DelayStart();
	...
if (DelayIsOver(delay1,time1) {DoSomething();};

Мы видим, что тонкости реализации спрятаны от пользователя (поскольку они ему не нужны, от слова "совсем"), набор сущностей минимален, обращение с ними просто и понятно - задача выполнена. На этом можно было бы и закончить, но в мире нет предела совершенству. Следует отметить, что дальнейшие варианты - это только "синтаксический сахар", позволяющий упростить и сделать более очевидным некоторые аспекты применения.
Например, способ фиксации момента начала отсчета не вполне очевиден (знак равенства как то загадочен), можно было бы реализовать его в следующем виде, хотя появляется знак &, которого нет во второй функции

void DelayStart(DelayType *delay) { *delay = millis(); };

DelayType delay1;
DelayStart(&delay1);
	...

Тогда можно упорядочить использование объекта в обоих функциях:

int DelayIsOver(DelayType *Delay, unsigned long Time) return ((millis() - *Delay) > Time)

	...
if (DelayIsOver(&delay1,time1) {DoSomething();};

Но тогда в обоих функциях появляется загадочный знак &, борьба с которым приводит нас к
Способ 3 - записи, которые и предназначены для облегчения работы с данными путем их группировки с функциями:

typedef struct {
  unsigned long delay;
  void DelayStart(void) {delay=millis();};
  int DelayIsOver(unsigned long Time) {return ((millis() - delay) > Time);};
} DelayType;

DelayType delay1;
delay1.DelayStart();
	...
if (delay1.DelayIsOver(time1) {DoSomething();};

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

Но мы то используем в среде Ардуино компилятор GCC, а он позволяет нам программировать на С++, так что следующий
Способ 4 - классы (спойлер - практически ничего не поменяется).
"Но тут настало утро и Шехрезада прекратила дозволенные речи"

 

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

ЕвгенийП пишет:

Подпишусь.

Чувствуешь нехватку агитации по повсеместному использованию МИСРА? ;)))

ssss
Offline
Зарегистрирован: 01.07.2016

МИСРА и говноделай... вещи несовместимые...

Каждый думает... что из делайговна конфетку слепить можно... )))))

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

wdrakula пишет:

Чувствуешь нехватку агитации по повсеместному использованию МИСРА? ;)))

Мисразм мне не страшен. Я давно уже (ещё до появления мисры) всем этим добром переболел (в абсолютно бессимптомной форме, впрочем) и теперь у меня стойкий иммунитет.

А чувствую потребность, может быть, когда-нибудь, увидеть как кто-то реализует, наконец, универсальный двухполюсник по уму - через иерархи. классов, так, чтобы покрывалось всё, что является двухполюсником, и чтобы каждая строчка кода реюзалась везде по 10 раз, ну, и, разумеется, чтобы это не требовало обязательного применения Меги и ещё чего потолще :-)

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

wdrakula
wdrakula аватар
Offline
Зарегистрирован: 15.03.2016

Вот прям любой двухполюсник? Или чем-то ограничимся?

Клапауций 12345
Offline
Зарегистрирован: 17.05.2020
 
русский анекдот: 
Мойша, когда Вас не было - они о вас такое говорили, такоеее говорили... 
Изя, передайте им, что, когда меня нет - они могут меня, даже, бить.
 
GarryC, при всём уважении - спрячьте это.
а, то как-то глупо оно выглядит:
 
=====
здрасте, всем.
GarryC
Offline
Зарегистрирован: 08.08.2016

Ну я разбирался в Гите, он для меня несколько непривычен, вполне может глупо выглядеть. Своего рода "проба пера".

Клапауций 12345
Offline
Зарегистрирован: 17.05.2020

GarryC пишет:

Ну я разбирался в Гите, он для меня несколько непривычен, вполне может глупо выглядеть. Своего рода "проба пера".


склонен, даже, поверить.
и, даже, не буду просить показать правильный код библиотеки для кнопок - ведь, его(кода) просто нет.
нет не потому, что ты не знаешь, как - "как" ты знаешь, даже начал писать об этом выше...
но код, почему-то не пишется.
много причин мне излагали за 5 лет с даты первой публикации титанового велосипеда - все причины очень уважительные :D

поэтому, какой смысл обсуждать титановый велосипед, если лучше ничего нет?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

wdrakula пишет:
Вот прям любой двухполюсник? Или чем-то ограничимся?
Это вопрос к разработке, а та - к поставленной задаче.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Клапауций 1488 пишет:
какой смысл обсуждать титановый велосипед, если лучше ничего нет?
Вы перепутали. Нет ничего лучше сала и солёного огурчика под прохладную водочку, а всё остальное относительно.

GarryC
Offline
Зарегистрирован: 08.08.2016

Продолжим с того места, на котором остановились и видим код

typedef class {
public:
  unsigned long delay;
  void DelayStart(void) {delay=millis();};
  int DelayIsOver(unsigned long Time) {return ((millis() - delay) > Time);};
} DelayType;

DelayType delay1;
delay1.DelayStart();
	...
if (delay1.DelayIsOver(time1) {DoSomething();};

Как я и обещал, ничего не изменилось (почти), мы всего лишь заменили record на class (выглядит странно, но так можно делать), но нам пришлось добавить описание секции public. Именно здесь и лежит разница между записями и классами - в записи все поля и методы доступны пользователю, а в классе только те, которые расположены в особо помеченной секции (тут есть тонкости, но для первого приближения достаточно).

Так вот, раз уж мы пошли на применение классов, то мы должны их использовать правильно и максимально ограничить доступные пользователю сущности (правильнее было бы ограничить их видимость, но это не в нашей власти). Примечание: вообще то в нашей власти и мы можем вообще скрыть детали реализации при помощи технологии Pimpl, но ее применение в данном контексте явно избыточно, поскольку наш потенциальный пользователь рассеян (придурковат), но не злонамерен, а это технология совсем не бесплатная. Вопрос о том, почему мы должны максимально прятать детали реализации от пользователя, явно выходит за пределы данного опуса, просто примем это требование как должное.

Поэтому правильное применение классов будет выглядеть несколько по иному (ну и заодно напишем его в привычной форме) :

class DelayType{
public:
  void DelayStart(void) {delay=millis();};
  int DelayIsOver(unsigned long Time) {return ((millis() - delay) > Time);};
private:
  unsigned long delay;
} DelayType;

DelayType delay1;
delay1.DelayStart();
	...
if (delay1.DelayIsOver(time1) {DoSomething();};

Что изменилось принципиально - если раньше пользователь мог написать что то вроде

...
delay1.delay*=3;
....

и получить совершенно непредсказуемое поведение, и в случае записи мы ничего не могли поделать с таким пользователем, то в случае правильного класса он сразу же получает по рукам от компилятора. Нет, конечно, если человек очень хочет выстрелить себе в ногу (взять указатель на объект класса, откастовать его и произвести выстрел), то помешать ему очень трудно, но, по крайней мере, мы ограничили его возможности сделать это случайно, но есть не нарочно. Далее мы будем рассматривать только реализацию в виде класса, обратное преобразование в запись и функции несложно и оставляется на долю пытливого читателя (который не является счастливым обладателем плюсов).

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

GarryC пишет:

пришлось добавить описание секции public. Именно здесь и лежит разница между записями и классами - в записи все поля и методы доступны пользователю, а в классе только те, которые расположены в особо помеченной секции (тут есть тонкости, но для первого приближения достаточно).

Изучи матчасть хорошенько.  В записях тоже есть и private и protected поля  и методы.  Мало того, их, матьиё, даже наследовать можно.  Запись от класса отличается только ускользающими от моего мозга деталями реализации, больше ничем. :) 

Прекрасно компилируется и работает 

struct TStruct1 {
private:
	uint8_t  Field1;
protected:
	uint8_t  Field2;
public:
	uint8_t Field3;
};

struct TStruct2 : public TStruct1 {
public:
	uint8_t Field4;
};

TStruct2 MyStruct;

Причём, снаружи у MyStruct  видны тока Field3 и Field4  :)   

	MyStruct.Field3 = MyStruct.Field4 = 100;

	Serial << MyStruct.Field3;

Ниажыданна. 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

когда то я тоже пытался, но в массы не пошло. :) 

http://arduino.ru/forum/programmirovanie/akh-eti-strashnye-slozhnye-milye-prostye-klassy

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

GarryC пишет:
заменили record на class
Какой record?

GarryC пишет:
раз уж мы пошли на применение классов, то мы должны их использовать правильно и максимально ограничить доступные пользователю сущности

Кто или что мешает сделать тоже самое (и так же точно) со структурой?

GarryC пишет:

Далее мы будем рассматривать только реализацию в виде класса

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

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Петрович, удали тогда мои посты #13 и #14.  Думаю, вам, корифеям есть что сказать больше, чем мне. 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Не прибедняйся. Да и говорить тут особо нечего. 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

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

GarryC
Offline
Зарегистрирован: 08.08.2016

И вот теперь то я могу начать любимый жанр "плач Ярославны" и покажу, что именно мне не понравилось в упомянутом ранее http://arduino.ru/forum/programmirovanie/klass-titanovyi-velosiped-stopwatch.

С позволения автора, я воспроизведу тут его творение и пример использования (опустив комментарии)

class StopWatch {
public:
  unsigned long previous;
  unsigned long interval;
  boolean event;

  StopWatch() {
    previous = millis();
    interval =        0;
    event    =        0;
  }

  void read(boolean _event) {
    event = _event;
    unsigned long current = millis();
    if (event == 1) {interval = current - previous; previous = current;}
  }
};
---
StopWatch StopWatch_01;
StopWatch_01.read(BUTTON_01.click_down); // подсчёт количества миллисекунд между двумя последними нажатиями кнопки.
if (StopWatch_01.interval <= 1000) {digitalWrite(15, 0);} // кнопка была нажата чаще или равно 1 раз в секунду.

и начну задавать вопросы:

1) Имеются 3 внутренние переменные (почему именно 3, об этом позже, мы обходились одной) и все  они представлены пользователю - зачем?

2) Доступ к одной из них, содержащей текущий рассчитанный интервал, осуществляется напрямую, а не через метод класса (геттер) - почему? Не надо мне рассказывать об эффективности, я сам категорический сторонник быстрого кода, но в данном конкретном случае не будет никакой разницы в генерируемом коде, а дыра налицо.
Примечание: раньше я думал, что доступ через виртуальный геттер будет сложнее и дольше, но оказалось, что это неверно и когда компилятор видит статически определенный объект, он генерит минимально возможный код - оптимизация, вот одна из причин, по которой я не буду писать свой компилятор С++, как бы не был недоволен существующими.

3) Переменная event вообще не используется, от слова "никак" - зачем она?

4) Почему не сделан метод сравнения с ожидаемым значением внутри класса, вместо этого сравнение осуществляется в программе пользователя - зачем?

5) Ну и теперь самое интересное - вместо двух методов, один из которых фиксирует начальное значение задержки, а второй рассчитывает истекший интервал (о необходимости подобного позже) имеется один метод с параметром - зачем?
Вот с этого место поговорим подробнее:
1. Понятность - в принятом авторе способе пользователь должен знать три сущности - сам метод, одно значение параметра и второе значение параметра, причем значения true и false ну никак не поясняют назначение параметра event  в сочетании с именем метода read. Если же использовать два метода с говорящими именами типа DelayStart и DelayValue? то пользователь должен помнит 2 сущности, причем перепутать их (мы же помним, что пользователь рассеян) намного сложнее.
2. Быстродействие -  поскольку в реализации все равно в зависимости от параметра производятся разные действия, вынос решения (при необходимости) за тело метода быстродейстия не ухудшает, а в определенных случаях (когда мы точно знаем, какой метод использовать) и увеличивает.

GarryC
Offline
Зарегистрирован: 08.08.2016

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

А по поводу разницы записи и класса - она есть:
первая часть - синтаксический сахар, который позволяет плоско записывать сущности наследованного класса, а не городить частокол из точек;
вторая часть - конструктор и деструктор, то есть функции, автоматически вызываемые на границах видимости объекта;
ну и наверное много чего еще, начиная с секции по умолчанию.

Где то мне попадалась фраза , вроде такой "весь ООП можно реаализовать, имея хороший препроцессор, за исключением конструкторов".

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

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

дак в структурах и конструкторы есть, не поверишь. :)  И деструкторы, и даже виртуальные. 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Да, всё ты знаешь, по гамбургскому счёту другой разницы нет, а та что есть - производная это этой главной. Только надо понимать, что  к тому, что там члены по умолчанию public, нужно добавить, что наследование тоже по умолчанию public:

class B { /* . . . */ };

// три строки ниже эквивалентны
class D : B { /* . . . */ };
class D : private  B { /* . . . */ };
struct D : private  B { /* . . . */ };

// три строки ниже эквивалентны
struct E : B { /* . . . */ };
struct E : public B { /* . . . */ };
class E : public B { /* . . . */ };

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

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

GarryC пишет:

А по поводу разницы записи и класса - она есть:

первая часть - синтаксический сахар, который позволяет плоско записывать сущности наследованного класса, а не городить частокол из точек

Вот в это я вапще не въехал.  

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

GarryC пишет:

А по поводу разницы записи и класса - она есть:
первая часть - синтаксический сахар, который позволяет плоско записывать сущности наследованного класса, а не городить частокол из точек;
вторая часть - конструктор и деструктор, то есть функции, автоматически вызываемые на границах видимости объекта;

Кто или что Вам мешает использовать конструкторы и деструкторы в struct? Религия? MISRA? Коронавирус? Может, Камасутра?

Я же Вам по-дружески посоветовал - изучите матчасть, а потом продолжайте. Зачем демонстрировать свою некомпетентность?

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

ЕвгенийП пишет:

Да, всё ты знаешь, по гамбургскому счёту другой разницы нет, а та что есть - производная это этой главной.

То, что наследование разное, я уже своим лбом и граблями усвоил.  А какова же главная разность? 

А, видимо, то что у полей видимость, по умолчанию, разная, я прав? 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, да. Только наследование и видимость членов - это не разные вещи, а одна и та же (идеологически) - вот она и есть главная.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Яссна, спасибо. 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

DetSimen пишет:

GarryC пишет:

синтаксический сахар, который позволяет плоско записывать сущности наследованного класса, а не городить частокол из точек

Вот в это я вапще не въехал.  

А чего тут понимать. ТС имел в виду, что при наследовании, к полям базовой структуры доступ через одну точку, а при вложенных структурах - нужно столько точек, сколько уровней вложенности. Про то, что при вложенных структурах к полям базовых тоже можно через одну точку обращаться, он просто не знает.

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

Клапауций 12345
Offline
Зарегистрирован: 17.05.2020

GarryC пишет:

И вот теперь то я могу начать любимый жанр "плач Ярославны" и покажу, что именно мне не понравилось в упомянутом ранее http://arduino.ru/forum/programmirovanie/klass-titanovyi-velosiped-stopwatch.

ссылка на обсуждаемый тобой код должна была быть в первом посте, а не являться мне внезапно здесь - я, вообще, считал, что ты обсуждаешь библиотеку для кнопок, а не секундомер.

GarryC пишет:

1) Имеются 3 внутренние переменные (почему именно 3, об этом позже, мы обходились одной) и все  они представлены пользователю - зачем?

мне неизвестно, как формализировать три используемые классом переменные в одну.

GarryC пишет:

2) Доступ к одной из них, содержащей текущий рассчитанный интервал, осуществляется напрямую, а не через метод класса (геттер) - почему? Не надо мне рассказывать об эффективности, я сам категорический сторонник быстрого кода, но в данном конкретном случае не будет никакой разницы в генерируемом коде, а дыра налицо.
Примечание: раньше я думал, что доступ через виртуальный геттер будет сложнее и дольше, но оказалось, что это неверно и когда компилятор видит статически определенный объект, он генерит минимально возможный код - оптимизация, вот одна из причин, по которой я не буду писать свой компилятор С++, как бы не был недоволен существующими.

потому, что на момент написания кода мне это было не важно...

GarryC пишет:

3) Переменная event вообще не используется, от слова "никак" - зачем она?

используется.

GarryC пишет:

4) Почему не сделан метод сравнения с ожидаемым значением внутри класса, вместо этого сравнение осуществляется в программе пользователя - зачем?

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

если бы я в примере выдал результат в печать(сериал или индикатор), то ты бы меня просил вписать в класс печать значений работы класса?

GarryC пишет:

5) Ну и теперь самое интересное - вместо двух методов, один из которых фиксирует начальное значение задержки, а второй рассчитывает истекший интервал (о необходимости подобного позже) имеется один метод с параметром - зачем?
Вот с этого место поговорим подробнее:
1. Понятность - в принятом авторе способе пользователь должен знать три сущности - сам метод, одно значение параметра и второе значение параметра, причем значения true и false ну никак не поясняют назначение параметра event  в сочетании с именем метода read. Если же использовать два метода с говорящими именами типа DelayStart и DelayValue? то пользователь должен помнит 2 сущности, причем перепутать их (мы же помним, что пользователь рассеян) намного сложнее.
2. Быстродействие -  поскольку в реализации все равно в зависимости от параметра производятся разные действия, вынос решения (при необходимости) за тело метода быстродейстия не ухудшает, а в определенных случаях (когда мы точно знаем, какой метод использовать) и увеличивает.

read(event) 
read(1) - секундомер взведён.
read(0) - секундомер считает.

================

дурь какая-то - 5-ть лет тому 10-ю строкам кода вынес мосг программисту, он целых 5-ть лет в себе это носил и, таки, предъявил мне сейчас.

спасибо.

 

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

GarryC пишет:
я не буду писать свой компилятор С++
Ну, слава те Господи, а то я уж беспокоиться начал.

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Клапа, рад тебя видеть!

Клапауций 12345
Offline
Зарегистрирован: 17.05.2020

Ворота пишет:

Клапа, рад тебя видеть!

привет.

GarryC
Offline
Зарегистрирован: 08.08.2016

Вы совершенно напрасно ТАК беспокоитесь - я ни в коей мере не собираюсь Вас учить программированию на С++, и использую Вашу библиотеку только как пример того, как делать не следует в надежде, что другие читатели данного форума в своих проектах не будут принимать решения по принципу
"потому, что на момент написания кода мне это было не важно..."

Раз уж Вы решили ответить на мои замечание (могу только приветствовать такое), то
на вопрос 1 - "почему ВСЕ переменные видны" Вы не ответили,
на вопрос 2 - "это не важно" - сильно сказано,
на вопрос 3 - да, Вы действительно используете переменную для временного хранения параметра вызова (Вы боитесь, что в процессе вызова millis() параметр испортится?), то есть это называется использовать. Написать в проверке if (_event ==1) нельзя по религиозным соображениям?
на вопрос 4 - Если руководствоваться Вашей логикой, то вообще все внутренние члены класса должны быть доступными, ведь любое их использование есть частное применение. В общем, Вы этой логике и следуете, так что в последовательности Вам не откажешь, но почему то такое мнение остается уделом небольшой группы программистов, я стараюсь пропагандировать общепринятый обратный подход
на вопрос 5 - если для Вас очевидно, что
"read(1) - секундомер взведён.
read(0) - секундомер считает.", то я обладаю не столь развитыми креативными способностями и предпочитаю понятные названия функций, из которых очевидно их назначение.

 

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

GarryC пишет:
использую Вашу библиотеку только как пример того, как делать не следует
Заодно, подавая новый такой пример.

GarryC
Offline
Зарегистрирован: 08.08.2016

И что именно из представленного класса Вас не устраивает?

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Вопрос ко мне? К деду? К Петровичу? Или к Клапауцию?

GarryC
Offline
Зарегистрирован: 08.08.2016

Ну, поскольку Вы сказали, что я подаю очередной пример, как делать не надо, то к Вам.

Вопрос относится именно к реализации на классе. Тут произошла неприятная накладка - когда я писал про структуру, то имел в виду именно структуры С, а положил реализацию для С++, что и послужило причиной недопонимания, но когда я увидел реплику про возможность конструктора в структуре (возможную только в С++), то все стало на свои места. Досадная оплошность, готов признать. Могу даже выложить реализацию "на чистом С", но, поскольку она откровенно неудобная, по сравнению с С++, не уверен, что это делать стоит, хотя ... оставляю на усмотрение читателей.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Дак ты ж к классам подходил, значит речь шла за С++.  Причем здесь чистосишные структуры? 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Я уже вапще нихрена не понимаю в этой теме. Отпишусь.

GarryC
Offline
Зарегистрирован: 08.08.2016

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

GarryC
Offline
Зарегистрирован: 08.08.2016

Приношу свои извинения всем, кого я (случайно, не нарочно) ввел в заблуждение. Способ номер 3 должен был выглядеть не лучше способа 3 в виде структур С:

typedef struct {
unsigned long Delay;
} DelayType;

inline void DelayStart(DelayType*delay) { delay->Delay = millis(); };
inkine int DelayIsOver(DelayType* Delay,unsigned int Time) {
return ((millis() - delay->Delay) > Time); };

DelayType delay1;
DelayStart(&delay1);
	...
if (DelayIsOver(&delay1,time1) {DoSomething();};

и лишь потом должны были показаться удобные варианты со структурами (они же классы) С++.

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

GarryC пишет:

когда я писал про структуру, то имел в виду именно структуры С, а положил реализацию для С++

Получается, ты сравнивал структуры Си с классами, которых там просто нет? Странная накладка. Или ты сравнивал сущности из разных языков? Ещё страньше!

А про "много точек" при использовании вложенных структур - тоже неприятная накладка? Но здесь отмазка про Си не проходит, т.к. использовать одну точку можно и в Си безо всяких проблем.

Не честнее ли просто признать, что ты довольно слабо представляешь себе, что такое классы - на уровне первой страницы учебника с простейшими примерами и не более того?

Вот именно поэтому, мне очень не хочется начинать объяснять тебе как надо разрабатывать класс и почему у тебя приведён вовсе не класс, а, как ты правильно выразился, нечто, что "почти ничем не отличается от Си-шной структуры". Я здесь на форуме читал как Петрович пытался объяснить как надо писать классы сначала Клапе, а потом Пуху. Результат был в обоих случаев одинаков - поциент не понял, что ему говорят в силу отсутствия базовых знаний, но воспринял своё непонимание как то, что ему несут пургу. Обозвал объясняющего мудаком и на это всё закончилось. Оно мне надо?

Так что извини. я не буду. Может Петрович в третий раз попробует, если ему не лень.

 

Клапауций 12345
Offline
Зарегистрирован: 17.05.2020

GarryC пишет:

Раз уж Вы решили ответить на мои замечание (могу только приветствовать такое), то

если так странно всё оборачивается, то неофитам и, просто, интересующимся - суть предъявы GarryC мне:

по порядку:

Вс, 02/10/2016 - 17:28 некий ползатель форума GarryC изрекает в теме кода секундомера религиозное проклятие.

GarryC пишет:

О, Господи !

#5 http://arduino.ru/forum/programmirovanie/klass-titanovyi-velosiped-stopwatch#comment-223425

Вс, 02/10/2016 - 17:41 ответил потерпевшему практически сразу:

Клапауций 232 пишет:

GarryC пишет:

О, Господи !

я тебя слушаю, раб мой.

кто тебя обидел?

*немного религиозной матчасти: я являюсь адептом Церкви Святаго Электричества и все проклятия в отношении меня зеркально поражают отправителя.

из сказанного выше становится понятно, почему GarryC пропал из поля моего зрения на 5-ть лет.

далее...

Вс, 17/05/2020 - 15:21 GarryC создаёт тему, где описывает произошедшее с ним недоразумение, козырем его аргументов является пост некоего RoN.

RoN пишет:

Клапауций 232, хотел спросить. У вас очень крутой код:)

Можно ли подключить тактовую кнопку на аналоговый вывод?

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

Заранее спасибо!

#11 http://arduino.ru/forum/programmirovanie/klass-titanovyi-velosiped-stopwatch#comment-334764

из этого поста, якобы, следует, что RoN восхищён крутостью кода секундомера и прямо сейчас готов отправиться в паломничество в Альпы дабы, собирать Молнии Святаго Электричества в лейденские банки и возлагать их на алтарь Науки.

всё как бы "да", но "нет".

в те далёкие времена, когда я писал титановый велосипед, RoN интересовался возможностью прикручивания к библиотеке для тактовой кнопки аналоговой кнопки.
т.к. личка на форуме отсутсвует - народ пытается обратить внимание собеседника в той теме, где собеседник был активен последнее время.
т.е. ещё раз: пост RoN #11 относится к теме класс титановый велосипед для тактовой кнопки.
 
исходя из выше мною искренне сказанного, обращаю рассеянное внимание GarryC на сей печальный факт.
 
иначе, как в анекдоте: деньги! "да" - деньги. но, не в лотерею, а в покер. и, не выиграл, а проиграл.
 
*по содержимому кода кратко: код продуман, вычитан, протестирован перед публикацией на форуме, все свои вопросы по коду секундомера - в тему кода и там вежливо спрашивать, а не здесь пиариться за мой очень скромный счёт.
возможно, я и отвечу... через 5-ть лет.
 
всем спасибо за внимание к странному.

 

Клапауций 12345
Offline
Зарегистрирован: 17.05.2020

Ворота пишет:

Результат был в обоих случаев одинаков - поциент не понял, что ему говорят в силу отсутствия базовых знаний, но воспринял своё непонимание как то, что ему несут пургу. Обозвал объясняющего мудаком и на это всё закончилось.

два варианта или их комбинация:
1. у Клапауция и Пуха отсутствуют базовые знания программирования.
2. у Петровича отсутствуют базовые педагогические умения и навыки.
 
Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Клапауций 1488 пишет:

два варианта или их комбинация:

1. у Клапауция и Пуха отсутствуют базовые знания программирования.
2. у Петровича отсутствуют базовые педагогические умения и навыки.

Так и есть. Либо одно, либо другое, либо смесь в некоторой пропорции. Но от этого никому не легче - результат на табло. Поэтому я в эту кашу не полезу.

GarryC
Offline
Зарегистрирован: 08.08.2016

Ну я ничего другого и не ожидал, ответы по существу были маловероятны, поскольку основный смысл единственного ответа "я об этом не подумал, мне это не представляется важным".

GarryC
Offline
Зарегистрирован: 08.08.2016

У меня к Вам, Ворота, есть только одно предложение - сначала прочитайте, потом пишите, хотя "чукча не читатель ...". Я в комментарии предельно четко объяснил свою ошибку - в том месте, где должны были быть структуры C, был приведен код для структур С++ (для Вас это будет неожиданностью, но они существенно различны). Поэтому дальнейшие описания недостатков структур именно языка С начали относится к структурам языка С++, что совершенно не верно. Поэтому недоуменный комментарий Петровича был совершенно уместен. После того, как  я дал разъяснения, Ваш комментарий становится, как бы сказать мягче, не вполне адекватным и показывает слабое знакомство с предметом обсуждения.
Конкретная фраза про много точек - привожу код на языке С:

typedef struct {
unsigned long Delay;
} DelayType;

typedef struct {
    DelayType delay;
    int count;
} SomeDelayExtension;
...
SomeDelayExtension DelayExt;
DelayExt.delay.Delay=23;

и предлагаю Вам, раз Вы так в этом разбираетесь, убрать лишние точки в последней строке и написать, как это возможно в структурах на С++, DelayExt.Delay=23, ведь "использовать одну точку можно и в Си безо всяких проблем"

 

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Значит, накосячил ты, а 

GarryC пишет:

слабое знакомство с предметом 

у меня? Забавный ты мужик!

GarryC пишет:
"использовать одну точку можно и в Си безо всяких проблем"

Разумеется, можно, но для этого недостаточно только

GarryC пишет:
убрать лишние точки в последней строке

для этого нужно структуру правильно описать. Тебе нужен пример?

GarryC
Offline
Зарегистрирован: 08.08.2016

Конечно же, жду с нетерпением.

Клапауций 12345
Offline
Зарегистрирован: 17.05.2020

GarryC пишет:

Ну я ничего другого и не ожидал, ответы по существу были маловероятны, поскольку основный смысл единственного ответа "я об этом не подумал, мне это не представляется важным".

Гарри, я пытался с тобой нормально общаться, но перечитав тему класс титановый велосипед для тактовой кнопки. увидел, что жопа у тебя начала гореть ещё тогда - сходи перечитай себя там, начиная отсюда #31

там я пытался вычистить всю эту дурь не по теме, но часть осталась - насладись собой там.

и посмотри на результат своего труда тут https://github.com/tGarryC/Buttons

где правильный код, пустомеля?