Детальное описание примеров

under construction


Примеры программ


Практические примеры декомпозиции задачи

Детальное описание примеров

Примеры означают практическую реализацию. Это самое слабое и скользкое место всей моей затеи. Я боролся с техническими подробностями, которые убивают внимание, направленное на решение задачи, как мог во время предыдущих глав. Но сейчас это делать уже нельзя. Единственное, на что я надеюсь, на хорошее знание С и С++ не объектно, которое позволит быстро понять о чем идет речь, т.к. в объектных конструкциях С++ програмист на С не найдет, скорее всего, ничего принципиально нового, изменились только их правила использования.

Что это за примеры

Практические примеры декомпозиции задачи

При выборе примеров я руководствовался следущими соображениями:

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

У меня был еще выбор:

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

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

Основная идея этих примеров - простота до максимума деталей описания, явно не нужных для решения, и без ущерба для решаемой задачи, даже с ущербом для надежности, но без перехода в ╚синтетичность╩ ( т.е. бессмысленность ) примера. Внимание уделяется только цепочке задача-модель-описание.

Примеры с нуля

Практические примеры декомпозиции задачи

Можно задать такие вопросы:

На эти вопросы есть элементарные ответы:

Все ли так хорошо

Практические примеры декомпозиции задачи

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

Даже самые элементарные примеры потребовали определенной продвинутости в знании С++ и ООП, что как раз хочется получить из этих примеров. От ряда свойств и идей пришлось совсем отказаться, а другие существенно упростить. Можно даже сказать, что подобрать хорошие и простые примеры не удалось, т.к. подобрать пример в котором бы сочетались простота, все свойства да еще от простого к сложному это уже искусство.

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

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

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


Примитивные определения (mydef.h)

Детальное описание примеров

Это простые определения, которые позволяют сделать работу по заданию основных параметров и для улучшения независимости от ОС в вашей программе. Реально, получается целое семейство этих mydef.h, для каждой ОС - свой файл. В этом файле есть несколько разделов.

Задание типов

Примитивные определения (mydef.h)

Как уже говорилось выше, для улучшения переноса программ на не flat модели, используется задание типов указателей на основные базовые с суффиксом _p, а так же удобное включение беззнаковости в целое с префиксом u_. В нужной модели вы правите только эту секцию. Это типы: u_int, u_int_p, int_p etc.

Типы для сохранения я решил не использовать в примерах, но сразу скажу, что не текстовые файлы конфигурации записанные в 32 разрядных ОС могут не читаться на 16 разрядных ОС и наоборот. Это происходит не от того, что текстовый файл ╚универсальнее╩. Просто текстовый файл - одна из форм кодирования, общедоступная и, на мой взгляд, не лучшая для некоторых применений, иногда требуется для старых программ связи. Мы же не будем даже пальцем шевелить в этом направлении, так как есть чем еще заниматься. Вобщем, я написал по этому поводу больше слов, чем трудность проблемы.

Обработка ошибок (err.cpp)

Примитивные определения (mydef.h)

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

Тип ошибки задан как перечислимый тип t_err. Глобальная переменная on_err у нас всегда означает ╚останов по ошибке╩.

Строку описания ошибки можно получить с помощью

    char_p    strerr(t_err err);
не спутайте со стандартной strerror().

Используемые макросы
    err(error)
вывести тип ошибки
    err2(error,msg)
ее же и сообщение
    warn(m)
вывести сообщение и продолжить работу
автоматически вставляют имя файла и строки места ошибки, как и assert() и вызывают системно-зависимую функцию вывода ошибки. Для WIN32 это

    t_err	errw32_(t_err error, char_p file, u_int line, char_p msg=0);
Система оповещения об ошибке в WIN32 вызовет модальное окно с кнопкой ОК.

Вот типичное использование фильтра ошибок. Я не люблю вставлять проверяемый код внутрь err(), т.к. сообщений больше, чем просто "assertion failed".
    //**********************
    t_err    my_fn(int);

    //**********************
    t_err    another_my_fn()
     {
      t_err    ret;
      if(
         ( (ret=my_fn(0))!=ERR_NO )
         ||( (ret=my_fn(1))!=ERR_NO )
        )
       return err(ret);
      warn(╚OK╩);
      return ERR_NO;
     }

    //**********************
    void main()
     {
      t_err    ret;
      if( (ret=my_another_fn())!=ERR_NO )
       {err2(ret, ╚все поломалось╩);return;}
     }

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

Простой ввод с текстового файла (getln.cpp)

Примитивные определения (mydef.h)

Прочитать строку из текстового файла в asciiz формат.

    t_err    getln(char_p buf, u_int max_len, FILE *fp);

Это работает для файлов, открытых как ╚rb╩. Признак конца строки \0x0A или EOF. Места в buf должно быть не менее чем max_len+\0 (допускается сочетание getln(0,0) - просто прочитать сроку и никуда не записать). Чтение останавливается после признака конца строки, запись после достижения max_len, т.е. излишки строки более max_len потеряются. Если в строке файла содержится символ \0, то он просто запишется и может вызвать ошибку определения длины прочитанной строки, если она не известна заранее. Символы \0x0D и \0x0A игнорируются не записываются в buf и не подсчитываются для max_len.

Такая функция удобна в тех файлах, где в первых позициях хранится нужная информация, а остальное надо пропустить до конца строки, для прокрутки строк и маркер конца строки записаный в текстовый файл как \r\n в DOS и как \n в UNIX работает правильно.


Детальное описание примеров