- •Глава 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.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.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.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.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.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.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.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.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.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.1 Цикл развития
Процесс развития системы - это итеративная деятельность. Основной
цикл сводится к повторяемым в следующей последовательности шагам:
[1] Создать общее описание проекта.
[2] Выделить стандартные компоненты.
[a] Подогнать компоненты под данный проект.
[3] Создать новые стандартные компоненты.
[a] Подогнать компоненты под данный проект.
[4] Составить уточненное описание проекта.
В качестве примера рассмотрим автомобильный завод. Проект должен
начинаться с самого общего описания новой машины. Этот первый шаг
базируется на некотором анализе и описании машины в самых общих
терминах, которые скорее относятся к предполагаемому использованию,
чем к характеристикам желаемых возможностей машины. Часто самой
трудной частью проекта бывает выбор желаемых возможностей, или,
точнее, определение относительно простого критерия выбора желаемых
возможностей. Удача здесь, как правило, является
результатом работы отдельного проницательного человека и часто
называется предвидением. Слишком типично как раз отсутствие
ясных целей, что приводит к неуверенно развивающимся или просто
проваливающимся проектам.
Итак, допустим необходимо создать машину среднего размера с
четырьмя дверцами и достаточно мощным мотором. Очевидно, что
на первом этапе проекта не следует начинать проектирование машины
(и всех ее компонентов) с нуля. Хотя программист или разработчик
программного обеспечения в подобных обстоятельствах поступит именно
так.
На первом этапе надо выяснить, какие компоненты доступны на
вашем собственном складе и какие можно получить от надежных
поставщиков. Найденные таким образом компоненты не обязательно
в точности подойдут для новой машины. Всегда требуется подгонка
компонентов. Может быть даже потребуется изменить характеристики
"следующей версии" выбранных компонентов, чтобы сделать их
пригодными для проекта. Например, может существовать вполне пригодный
мотор, вырабатывающий немного меньшую мощность.Тогда
или вы, или поставщик мотора должны предложить, не изменяя общего
описания проекта, в качестве компенсации дополнительный
зарядный генератор. Заметим, что сделать это,"не изменяя общего описания
проекта", маловероятно, если только само описание не приспособлено
к определенной подгонке. Обычно подобная
подгонка требует кооперации между вами и поставщиком моторов.
Сходные вопросы возникают и у программиста или разработчика
программного обеспечения. Здесь подгонку обычно облегчает эффективное
использование производных классов. Но не рассчитывайте провести
произвольные расширения в проекте без определенного предвидения
или кооперации с создателем таких классов.
Когда исчерпается набор подходящих стандартных компонентов,
проектировщик машины не спешит заняться проектированием новых
оптимальных компонентов для своей машины. Это было бы слишком
расточительно. Допустим, что не нашлось подходящего блока
кондиционирования воздуха, зато есть свободное пространство, имеющее
форму буквы L, в моторном отсеке. Возможно решение разработать
блок кондиционирования указанной формы. Но вероятность того, что
блок подобной странной формы будет использоваться в машинах другого
типа (даже после значительной подгонки), крайне низка. Это означает,
что наш проектировщик машины не сможет разделить затраты на
производство такого блока с создателями машин другого типа, а значит
время жизни этого блока коротко. Поэтому стоит спроектировать блок,
который найдет более широкое применение, т.е. разработать
разумный проект блока, более приспособленный для подгонки, чем наше
L-образное чудище. Возможно, это потребует больших усилий, и даже
придется для приспособления более универсального блока изменить
общее описание проекта машины. Поскольку новый блок разрабатывался
для более общего применения, чем наше L-образное чудище,
предположительно, для него потребуется некоторая подгонка, чтобы
полностью удовлетворить наши пересмотренные запросы.
Подобная же альтернатива возникает и у программиста или разработчика
программного обеспечения: вместо того, чтобы создать программу,
привязанную к конкретному проекту, разработчик может спроектировать
новую достаточно универсальную программу, которая будет иметь
хорошие шансы стать стандартной в определенной области.
Наконец, когда мы прошлись по всем стандартным компонентам,
составляется "окончательное" общее описание проекта. Несколько
специально разработанных средств указываются как возможные. Вероятно,
в следующем году придется для новой модели повторить наши шаги,
и как раз эти специальные средства придется переделать или выбросить.
Как ни печально, но опыт традиционно проектировавшихся программ
показывает, что лишь несколько частей системы можно выделить в
отдельные компоненты и лишь несколько из них пригодны вне
данного проекта.
Мы не пытаемся утверждать, что все разработчики машин
действуют столь разумно, как в приведенном примере, а разработчики
программ совершают все указанные ошибки. Утверждается, что указанная
методика разработки машин применима и для программного обеспечения.
Так, в этой и следующей главах даны приемы использования ее для С++.
Тем не менее можно сказать, что сама природа программирования
способствует совершению указанных ошибок ($$12.2.1 и $$12.2.5).
В разделе 11.4.3 опровергается профессиональное предубеждение против
использования описанной здесь модели проектирования.
Заметим, что модель развития программного обеспечения хорошо
применима только в расчете на большие сроки. Если ваш горизонт
сужается до времени выдачи очередной версии, нет смысла создавать
и поддерживать функционирование стандартных компонентов. Это
просто приведет к излишним накладным расходам. Наша модель
рассчитана на организации со временем жизни, за которое проходит
несколько проектов, и с размерами, которые позволяют нести
дополнительные расходы и на средства проектирования, программирования,
и на сопровождение проектов, и на повышение квалификации разработчиков,
программистов и менеджеров. Фактически это эскиз некоторой фабрики по
производству программ. Как ни удивительно, она только масштабом
отличается от действий лучших программистов, которые для повышения своей
производительности в течении лет накапливали запас приемов и методов
проектирования, создавали инструменты и библиотеки. Похоже, что
большинство организаций просто не умеет воспользоваться достижениями
лучших сотрудников, как из-за отсутствия предвидения, так и по
неспособности применить эти достижения в достаточно широком
объеме.
Все-таки неразумно требовать, чтобы "стандартные компоненты"
были стандартными универсально. Существует лишь малое число
международных стандартных библиотек, а в своем большинстве компоненты
окажутся стандартными только в пределах страны, отрасли, компании,
производственной цепочки, отдела или области приложения и т.д.
Просто мир слишком велик, чтобы универсальный стандарт
всех компонентов и средств был реальной или желанной целью проекта.