
- •4.1 Введение 109
- •6.1 Введение и краткий обзор 170
- •7.1 Введение 206
- •8.1 Введение 232
- •9.1 Обработка ошибок 264
- •10.1 Введение 293
- •11.1 Введение 323
- •13.1 Введение 382
- •Предварительные замечания
- •Структура книги
- •Глава 6 посвящена понятию производных классов, которое позволяет строить
- •Раздел 3.4 главы 2. Для обозначения справочного руководства применяется
- •1.1 Введение
- •1.2 Парадигмы программирования
- •1.2.1 Процедурное программирование
- •1.2.2 Модульное программирование
- •1.2.3 Абстракция данных
- •1.2.4 Пределы абстракции данных
- •1.2.5 Объектно-ориентированное программирование
- •1.3 "Улучшенный с"
- •1.3.1 Программа и стандартный вывод
- •1.3.2 Переменные и арифметические операции
- •1.3.3 Указатели и массивы
- •1.3.4 Условные операторы и циклы
- •1.3.5 Функции
- •1.3.6 Модули
- •1.4 Поддержка абстракции данных
- •1.4.1 Инициализация и удаление
- •1.4.2 Присваивание и инициализация
- •1.4.3 Шаблоны типа
- •1.4.4 Обработка особых ситуаций
- •1.4.5 Преобразования типов
- •1.4.6 Множественные реализации
- •1.5 Поддержка объектно-ориентированного программирования
- •1.5.1 Механизм вызова
- •1.5.2 Проверка типа
- •1.5.3 Множественное наследование
- •1.5.4 Инкапсуляция
- •1.6 Пределы совершенства
- •* Глава 2. Описания и константы
- •2.1 Описания
- •2.1.1 Область видимости
- •2.1.2 Объекты и адреса
- •2.1.3 Время жизни объектов
- •2.2 Имена
- •2.3 Типы
- •2.3.1 Основные типы
- •2.3.2 Неявное преобразование типа
- •2.3.3 Производные типы
- •2.3.5 Указатели
- •2.3.6 Массивы
- •2.3.7 Указатели и массивы
- •2.3.8 Структуры
- •2.3.9 Эквивалентность типов
- •2.3.10 Ссылки
- •2.4 Литералы
- •2.4.1 Целые константы
- •2.4.2 Константы с плавающей точкой
- •2.4.3 Символьные константы
- •2.4.4 Строки
- •2.4.5 Нуль
- •2.5 Поименованные константы
- •2.5.1. Перечисления
- •2.6. Экономия памяти
- •2.6.1 Поля
- •2.6.2. Объединения
- •2.7 Упражнения
- •* Глава 3. Выражения и операторы
- •3.1 Калькулятор
- •3.1.1 Анализатор
- •3.1.2 Функция ввода
- •3.1.3 Таблица имен
- •3.1.4 Обработка ошибок
- •3.1.5 Драйвер
- •3.1.6 Параметры командной строки
- •3.2 Сводка операций
- •3.2.1 Скобки
- •3.2.2 Порядок вычислений
- •3.2.3 Инкремент и декремент
- •3.2.4 Поразрядные логические операции
- •3.2.5 Преобразование типа
- •3.2.6 Свободная память
- •3.3 Сводка операторов
- •3.3.1 Выбирающие операторы
- •3.3.2 Оператор goto
- •3.4 Комментарии и расположение текста
- •3.5 Упражнения
- •* Глава 4
- •4.1 Введение
- •4.2 Связывание
- •4.3 Заголовочные файлы
- •4.3.1 Единственный заголовочный файл
- •4.3.2 Множественные заголовочные файлы
- •4.4 Связывание с программами на других языках
- •4.5 Как создать библиотеку
- •4.6 Функции
- •4.6.1 Описания функций
- •4.6.2 Определения функций
- •4.6.3 Передача параметров
- •4.6.4 Возвращаемое значение
- •4.6.5 Параметр-массив
- •4.6.6 Перегрузка имени функции
- •4.6.7 Стандартные значения параметров
- •4.6.8 Неопределенное число параметров
- •4.6.9 Указатель на функцию
- •4.7 Макросредства
- •4.8 Упражнения
- •* Глава 5. Классы
- •5.1 Введение и краткий обзор
- •5.2 Классы и члены
- •5.2.1 Функции-члены
- •5.2.2 Классы
- •5.2.3 Ссылка на себя
- •5.2.4 Инициализация
- •5.2.5 Удаление
- •5.2.6 Подстановка
- •5.3 Интерфейсы и реализации
- •5.3.1 Альтернативные реализации
- •5.3.2 Законченный пример класса
- •5.4 Еще о классах
- •5.4.1 Друзья
- •5.4.2 Уточнение имени члена
- •5.4.3 Вложенные классы
- •5.4.4 Статические члены
- •5.4.5 Указатели на члены
- •5.4.6 Структуры и объединения
- •5.5 Конструкторы и деструкторы
- •5.5.1 Локальные переменные
- •5.5.2 Статическая память
- •5.5.3 Свободная память
- •5.5.4 Объекты класса как члены
- •5.5.5 Массивы объектов класса
- •5.5.6 Небольшие объекты
- •5.6 Упражнения
- •* Глава 6
- •6.1 Введение и краткий обзор
- •6.2 Производные классы
- •6.2.1 Функции-члены
- •6.2.2 Конструкторы и деструкторы
- •6.2.3 Иерархия классов
- •6.2.4 Поля типа
- •6.2.5 Виртуальные функции
- •6.3 Абстрактные классы
- •6.4 Пример законченной программы
- •6.4.1 Монитор экрана
- •6.4.2 Библиотека фигур
- •6.4.3 Прикладная программа
- •6.5 Множественное наследование
- •6.5.1 Множественное вхождение базового класса
- •6.5.2 Разрешение неоднозначности
- •6.5.3 Виртуальные базовые классы
- •6.6 Контроль доступа
- •6.6.1 Защищенные члены
- •6.6.2 Доступ к базовым классам
- •6.7 Свободная память
- •6.7.1 Виртуальные конструкторы
- •6.7.2 Указание размещения
- •6.8 Упражнения
- •* Глава 7
- •7.1 Введение
- •7.2 Операторные функции
- •7.2.1 Бинарные и унарные операции
- •7.2.2 Предопределенные свойства операций
- •7.2.3 Операторные функции и пользовательские типы
- •7.3 Пользовательские операции преобразования типа
- •7.3.1 Конструкторы
- •7.3.2 Операции преобразования
- •7.3.3 Неоднозначности
- •7.4 Литералы
- •7.5 Большие объекты
- •7.6 Присваивание и инициализация
- •7.7 Индексация
- •7.8 Вызов функции
- •7.9 Косвенное обращение
- •7.10 Инкремент и декремент
- •7.11 Строковый класс
- •7.12 Друзья и члены
- •7.13 Предостережения
- •7.14 Упражнения
- •* Глава 8. Шаблоны типа
- •8.1 Введение
- •8.2 Простой шаблон типа
- •8.3 Шаблоны типа для списка
- •8.3.1 Список с принудительной связью
- •8.3.2 Список без принудительной связи
- •8.3.3 Реализация списка
- •8.3.4 Итерация
- •8.4 Шаблоны типа для функций
- •8.4.1 Простой шаблон типа для глобальной функции
- •8.4.2 Производные классы позволяют ввести новые операции
- •8.4.3 Передача операций как параметров функций
- •8.4.4 Неявная передача операций
- •8.4.5 Введение операций с помощью параметров шаблонного класса
- •8.5 Разрешение перегрузки для шаблонной функции
- •8.6 Параметры шаблона типа
- •8.7 Шаблоны типа и производные классы
- •8.7.1 Задание реализации с помощью параметров шаблона
- •8.8 Ассоциативный массив
- •8.9 Упражнения
- •* Глава 9
- •9.1 Обработка ошибок
- •9.1.1 Особые ситуации и традиционная обработка ошибок
- •9.1.2 Другие точки зрения на особые ситуации
- •9.2 Различение особых ситуаций
- •9.3 Имена особых ситуаций
- •9.3.1 Группирование особых ситуаций
- •9.3.2 Производные особые ситуации
- •9.4 Запросы ресурсов
- •9.4.1 Конструкторы и деструкторы
- •9.4.2 Предостережения
- •9.4.3 Исчерпание ресурса
- •9.4.4 Особые ситуации и конструкторы
- •9.5 Особые ситуации могут не быть ошибками
- •9.6 Задание интерфейса
- •9.6.1 Неожиданные особые ситуации
- •9.7 Неперехваченные особые ситуации
- •9.8 Другие способы обработки ошибок
- •9.9 Упражнения
- •* Глава 10. Потоки
- •10.1 Введение
- •10.2 Вывод
- •10.2.1 Вывод встроенных типов
- •10.2.2 Вывод пользовательских типов
- •10.3 Ввод
- •10.3.1 Ввод встроенных типов
- •10.3.2 Состояния потока
- •10.3.3 Ввод пользовательских типов
- •10.4 Форматирование
- •10.4.1 Класс ios
- •10.4.1.1 Связывание потоков
- •10.4.1.2 Поля вывода
- •10.4.1.3 Состояние формата
- •10.4.1.4 Вывод целых
- •10.4.1.5 Выравнивание полей
- •10.4.1.6 Вывод плавающих чисел.
- •10.4.2 Манипуляторы
- •10.4.2.1 Стандартные манипуляторы ввода-вывода
- •10.4.3 Члены ostream
- •10.4.4 Члены istream
- •10.5 Файлы и потоки
- •10.5.1 Закрытие потоков
- •10.5.2 Строковые потоки
- •10.5.3 Буферизация
- •10.6 Ввод-вывод в с
- •10.7 Упражнения
- •* Проектирование и развитие
- •11.1 Введение
- •11.2 Цели и средства
- •11.3 Процесс развития
- •11.3.1 Цикл развития
- •11.3.2 Цели проектирования
- •11.3.3 Шаги проектирования
- •11.3.3.1 Шаг 1: определение классов
- •11.3.3.2 Шаг 2: определение набора операций
- •11.3.3.3 Шаг 3: указание зависимостей
- •11.3.3.4 Шаг 4: определение интерфейсов
- •11.3.3.5 Перестройка иерархии классов
- •11.3.3.6 Использование моделей
- •11.3.4 Эксперимент и анализ
- •11.3.5 Тестирование
- •11.3.6 Сопровождение
- •11.3.7 Эффективность
- •11.4 Управление проектом
- •11.4.1 Повторное использование
- •11.4.2 Размер
- •11.4.3 Человеческий фактор
- •11.5 Свод правил
- •11.6 Список литературы с комментариями
- •12.1 Проектирование и язык программирования.
- •12.1.1 Игнорирование классов
- •12.1.2 Игнорирование наследования
- •12.1.3 Игнорирование статического контроля типов
- •12.1.4 Гибридный проект
- •12.2 Классы
- •12.2.1 Что представляют классы?
- •12.2.2 Иерархии классов
- •12.2.3 Зависимости в рамках иерархии классов.
- •12.2.4 Отношения принадлежности
- •12.2.5 Принадлежность и наследование
- •12.2.6 Отношения использования
- •12.2.7 Отношения внутри класса
- •12.2.7.1 Инварианты
- •12.2.7.2 Инкапсуляция
- •12.2.8 Программируемые отношения
- •12.3 Компоненты
- •12.4 Интерфейсы и реализации
- •12.5 Свод правил
- •* Проектирование библиотек
- •13.1 Введение
- •13.2 Конкретные типы
- •13.3 Абстрактные типы
- •13.4 Узловые классы
- •13.5 Динамическая информация о типе
- •13.5.1 Информация о типе
- •13.5.2 Класс Type_info
- •13.5.3 Как создать систему динамических запросов о типе
- •13.5.4 Расширенная динамическая информация о типе
- •13.5.5 Правильное и неправильное использование динамической
- •13.6 Обширный интерфейс
- •13.7 Каркас области приложения
- •13.8 Интерфейсные классы
- •13.9 Управляющие классы
- •13.10 Управление памятью
- •13.10.1 Сборщик мусора
- •13.10.2 Контейнеры и удаление
- •13.10.3 Функции размещения и освобождения
- •13.11 Упражнения
11.3 Процесс развития
Процесс развития программного обеспечения - это итеративный и
расширяющийся процесс. По мере развития каждая стадия повторяется
многократно, и при всяком возврате на некоторую стадию процесса уточняется
конечный продукт, получаемый на этой стадии. В общем случае процесс
не имеет ни начала, ни конца, поскольку, проектируя и реализуя систему,
вы начинаете, используя как базу другие проекты, библиотеки и прикладные
системы, в конце работы после вас остается описание проекта и программа,
которые другие могут уточнять, модифицировать, расширять и переносить.
Естественно конкретный проект имеет определенное начало и конец, и
важно (хотя часто удивительно трудно) четко и строго ограничить время
и область действия проекта. Но заявление, что вы начинаете с "чистого
листа", может привести к серьезным проблемам для вас, также как и позиция,
что после передачи окончательной версии - хоть потоп, вызовет
серьезные проблемы для ваших последователей (или для вас в новой
роли).
Из этого вытекает, что следующие разделы можно читать в любом
порядке, поскольку вопросы проектирования и реализации могут в
реальном проекте переплетаться почти произвольно. Именно, "проект"
почти всегда подвергается перепроектированию на основе предыдущего
проекта, определенного опыта реализации, ограничений, накладываемых
сроками, мастерством работников, вопросами совместимости и т.п.
Здесь основная трудность для менеджера или разработчика или
программиста в том, чтобы создать такой порядок в этом процессе,
который не препятствует усовершенствованиям и не запрещает повторные
проходы, необходимые для успешного развития.
У процесса развития три стадии:
- Анализ: определение области задачи.
- Проектирование: создание общей структуры системы.
- Реализация: программирование и тестирование.
Не забудьте об итеративной природе этих процессов (неспроста стадии
не были пронумерованы), и заметьте, что никакие важные аспекты процесса
развития программы не выделяются в отдельные стадии, поскольку они
должны допускать:
- Экспериментирование.
- Тестирование.
- Анализ проектирования и реализации.
- Документирование.
- Сопровождение.
Сопровождение программного обеспечения рассматривается просто как
еще несколько проходов по стадиям процесса развития (см. также
$$11.3.6).
Очень важно, чтобы анализ, проектирование и реализация не были
слишком оторваны друг от друга, и чтобы люди, принимающие в них
участие, были одного уровня квалификации для налаживания эффективных
контактов.
В больших проектах слишком часто бывает иначе. В идеале, в процессе
развития проекта работники должны сами переходить с одной стадии на
другую: лучший способ передачи тонкой информации - это использовать
голову работника. К сожалению, в организациях часто устанавливают
барьеры для таких переходов, например, у разработчика может быть
более высокий статус и (или) более высокий оклад, чем у "простого"
программиста. Не принято, чтобы сотрудники ходили по отделам с целью
набраться опыта и знаний, но пусть, по крайней мере, будут
регулярными собеседования сотрудников, занятых на разных стадиях проекта.
Для средних и малых проектов обычно не делают различия между
анализом и проектированием - эти стадии сливаются в одну. Для малых
проектов также не разделяют проектирование и программирование.
Конечно, тем самым решается проблема взаимодействия. Для данного
проекта важно найти подходящую степень формализации и выдержать
нужную степень разделения между стадиями ($$11.4.2). Нет единственно
верного способа для этого.
Приведенная здесь модель процесса развития программного обеспечения
радикально отличается от традиционной модели "каскад" (waterfall).
В последней процесс развития протекает линейно от стадии анализа до
стадии тестирования. Основной недостаток модели каскад тот, что в ней
информация движется только в одном направлении. Если выявлена
проблема "ниже по течению", то возникает сильное методологическое
и организационное давление, чтобы решить проблему на данном уровне,
не затрагивая предыдущих стадий процесса. Отсутствие повторных
проходов приводит к дефектному проекту, а в результате локального
устранения проблем получается искаженная реализация. В тех
неизбежных случаях, когда информация должна быть передана назад к
источнику ее получения и вызвать изменения в проекте, мы получим
лишь слабое "колыхание" на всех уровнях системы, стремящейся подавить
внесенное изменение, а значит система плохо приспособлена к
изменениям. Аргумент в пользу "никаких изменений" или "только локальные
изменения" часто сводится к тому, что один отдел не хочет
перекладывать большую работу на другой отдел "ради их же блага".
Часто бывает так, что ко времени, когда ошибка уже найдена, исписано
столько бумаги относительно ошибочного решения, что усилия,
нужные на исправление документации, затмевают усилия для исправления
самой программы. Таким образом, бумажная работа может стать главной
проблемой процесса создания системы. Конечно, такие проблемы могут быть
и возникают в процессе развития больших систем. В конце концов,
определенная работа с бумагами необходима. Но выбор линейной модели
развития (каскад) многократно увеличивает вероятность, что эта
проблема выйдет из-под контроля.
Недостаток модели каскад в отсутствии повторных проходов и
неспособности реагировать на изменения. Опасность предлагаемой здесь
итеративной модели состоит в искушении заменить размышление и
реальное развитие на последовательность бесконечных изменений.
Тот и другой недостатки легче указать, чем устранить, и для того,
кто организует работу, легко принять простую активность за реальный
прогресс.
Вы можете уделять пристальное внимание деталям, использовать
разумные приемы управления, развитую технологию, но ничто не спасет
вас, если нет ясного понимания того, что вы пытаетесь создать. Больше
всего проектов проваливалось именно из-за отсутствия хорошо
сформулированных реалистичных целей, а не по какой-либо иной причине.
Что бы вы не делали и чем бы не занимались, надо ясно представлять
имеющиеся у вас средства, ставить достижимые цели и ориентиры и не
искать технических решений социологических проблем. С другой стороны,
надо применять только адекватную технологию, даже если она потребует
затрат,- люди работают лучше, имея адекватные средства и приемлемую
среду. Не заблуждайтесь, думая, что легко выполнить эти рекомендации.