- •Предварительные замечания
- •Структура книги
- •Глава 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.4 Тип void
- •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.4 Эксперимент и анализ
В начале честолюбивого проекта нам неизвестен лучший способ построения
системы. Часто бывает так, что мы даже не знаем точно, что должна
делать система, поскольку конкретные факты прояснятся только в процессе
построения, тестирования и эксплуатации системы. Как задолго до
создания законченной системы получить сведения, необходимые для
понимания того, какие решения при проектировании окажутся
существенными, и к каким последствиям они приведут?
Нужно проводить эксперименты. Конечно, нужен анализ проекта и его
реализации, как только появляется пища для него. Преимущественно
обсуждение вертится вокруг альтернатив при проектировании и
реализации. За исключением редких случаев проектирование есть
социальная активность, которая ведет по пути презентации и
обсуждений. Часто самым важным средством проектирования оказывается
простая грифельная доска; без нее идеи проекта, находящиеся в
зародыше, не могут развиться и стать общим достоянием в среде
разработчиков и программистов.
Похоже, что самый популярный способ проведения эксперимента сводится
к построению прототипа, т.е. уменьшенной версии системы. Прототип не
обязан удовлетворять характеристикам реальных систем, обычно в
изобилии есть машинные ресурсы и программная поддержка, и в таких
условиях программисты и разработчики становятся непривычно опытными,
хорошо образованными и активными. Появляется цель - сделать
работающий прототип как можно скорее, чтобы начать исследование
вариантов проекта и способов реализации.
Такой подход, если применять его разумно, может привести к
успеху. Но он также может служить оправданием неудачно сделанных
систем. Дело в том, что уделяя особое внимание прототипу, можно
прийти к смещению усилий от "исследование вариантов
проекта" к "получение как можно скорее рабочей версии системы".
Тогда быстро угаснет интерес к внутренней структуре прототипа
("ведь это только прототип"), а работа по проектированию будет
вытесняться манипулированием с реализацией прототипа. Просчет
заключается в том, что такая реализация может легко привести к системе,
которая имеет вид "почти законченной", а по сути является пожирателем
ресурсов и кошмаром для тех, кто ее сопровождает. В этом
случае на прототип тратятся время и энергия, которые лучше приберечь
для реальной системы. Для разработчиков и менеджеров есть искушение
переделать прототип в конечный программный продукт, а "искусство
настройки системы" отложить до выпуска следующей версии. Если идти
таким путем, то прототипы отрицают все основы проектирования.
Сходная проблема возникает, если исследователи привязываются
к тем средствам, которые они создали при построении прототипа,
и забывают, что они могут оказаться непригодными для
рабочей системы, и что свобода от ограничений и формальностей, к
которой они привыкли, работая в небольшой группе, может оказаться
невозможной в большом коллективе, бьющимся над устранением длинной
цепи препятствий.
И в то же время создание прототипов может сыграть важную роль.
Рассмотрим, например, проектирование пользовательского интерфейса. Для
этой задачи внутренняя структура той части системы, которая прямо не
общается с пользователем, обычно не важна, и использование прототипов -
это единственный способ узнать,
какова будет реакция пользователя при работе с системой.
Другим примером служат прототипы, прямо предназначенные для изучения
внутренней структуры системы. Здесь уже интерфейс с пользователем
может быть примитивным, возможна работа с моделью пользователей.
Использование прототипов - это способ экспериментирования.
Ожидаемый результат - это более глубокое понимание целей, а не
сам прототип. Возможно, сущность прототипа заключается в том,
что он является настолько неполным, что может служить лишь средством
для эксперимента, и его нельзя превратить в конечный продукт без
больших затрат на перепроектирование и на другую реализацию. Оставляя
прототип "неполным", мы тем самым переключаем внимание на
эксперимент и уменьшаем опасность превращения прототипа в законченный
продукт. Это также почти избавляет от искушения взять за основу
проекта системы проект прототипа, при этом забывая или игнорируя те
ограничения, которые внутренне присущи прототипу. После эксперимента
прототип надо просто выбросить.
Не следует забывать о других способах проведения эксперимента,
которые могут служить во многих случаях альтернативой созданию прототипа,
и там, где они применимы, их использование предпочтительнее, поскольку
они обладают большей точностью и требуют меньших затрат
времени разработчика и ресурсов системы. Примерами могут служить
математические модели и различные формы моделирования. По сути,
существует бесконечная возрастающая последовательность,
начиная от математических моделей,
ко все более и более детальным способам моделирования, затем к
прототипам, к частичным реализациям системы, вплоть до полной системы.
Это подводит к идее построения системы, исходя из начального
проекта и реализации, и двигаясь путем повторного прохождения
этапов проектирования и реализации. Это идеальная стратегия,
но она предъявляет высокие требования к средствам проектирования
и реализации, и в ней содержится определенный риск того, что
программный объем, реализующий решения, принятые
при начальном проектировании, в процессе развития вырастет до такой
величины, что существенное улучшение проекта будет просто невозможно.
Похоже, что по крайней мере теперь такую стратегию применяют
или в проектах от малого до среднего размеров, т.е. там, где
маловероятны переделки общего проекта, или же для перепроектирования
и иной реализации после выдачи первоначальной версии системы, где
указанная стратегия становится неизбежной.
Помимо экспериментов, предназначенных для оценки решений,
принимаемых на этапе проектирования, источником получения полезной
информации может быть анализ собственно проектирования и (или)
реализации. Например, может оказаться полезным изучение различных
зависимостей между классами (см.$$ 12.2), не следует забывать и о
таких традиционных вспомогательных средствах реализации, как
граф вызовов функций, оценка производительности и т.п.
Заметим, что спецификация (результат анализа системы) и проект
могут содержать ошибки, как и реализация, и возможно, они даже
больше подвержены ошибкам, т.к. являются менее точными, не могут быть
проверены на практике и обычно не окружены такими развитыми средствами,
как те, что служат для анализа и проверки реализации. Введение
большей формализации в язык или запись, с помощью которой изложен проект,
в какой-то степени облегчает использования этих средств для
проектирования. Но, как сказано в $$12.1.1, это нельзя делать
за счет ухудшения языка, используемого для реализации. К тому
же формальная запись может сама стать источником трудностей и
проблем. Это происходит, когда выбранная степень формализации плохо
подходит для конкретных задач, когда строгость формализации превосходит
математическую основу системы и квалификацию разработчиков и
программистов, и когда формальное описание системы начинает
расходиться с реальной системой, для которой оно предназначалось.
Заключение о необходимости опыта и о том, что проектирование
неизбежно сопровождается ошибками и плохо поддержано программными
средствами, служит основным доводом в пользу итеративной модели
проектирования и реализации. Альтернатива - это линейная модель
процесса развития, начиная с анализа и кончая тестированием, но
она существенно дефектна, поскольку не допускает повторных
проходов, исходя из опыта, полученного на различных этапах развития
системы.