- •Глава 6 посвящена понятию производных классов, которое позволяет строить
- •Раздел 3.4 главы 2. Для обозначения справочного руководства применяется
- •1991 Г.Г. (такие как множественное наследование, статические функции-члены
- •1.1 Введение
- •1.2 Парадигмы программирования
- •1.2.1 Процедурное программирование
- •1.2.5 Объектно-ориентированное программирование
- •1.5 Поддержка объектно-ориентированного программирования
- •1.5.1 Механизм вызова
- •1.5.2 Проверка типа
- •1.5.3 Множественное наследование
- •1.6 Пределы совершенства
- •2.2 Имена
- •2.3.2 Неявное преобразование типа
- •2.4 Литералы
- •2.4.4 Строки
- •2.6. Экономия памяти
- •2.6.1 Поля
- •3.1.1 Анализатор
- •3.1.2 Функция ввода
- •3.2 Сводка операций
- •3.2.3 Инкремент и декремент
- •3.2.5 Преобразование типа
- •3.2.6 Свободная память
- •3.3.2 Оператор goto
- •4.1 Введение
- •4.3.1 Единственный заголовочный файл
- •4.3.2 Множественные заголовочные файлы
- •4.4 Связывание с программами на других языках
- •4.6.3 Передача параметров
- •5.1 Введение и краткий обзор
- •5.3.1 Альтернативные реализации
- •5.3.2 Законченный пример класса
- •Vector и matrix, мы могли бы обойтись без контроля индекса при
- •5.4.5 Указатели на члены
- •5.4.6 Структуры и объединения
- •5.5.3 Свободная память
- •5.5.5 Массивы объектов класса
- •6.1 Введение и краткий обзор
- •6.2.3 Иерархия классов
- •6.2.4 Поля типа
- •6.4.1 Монитор экрана
- •6.5 Множественное наследование
- •7.1 Введение
- •7.3 Пользовательские операции преобразования типа
- •7.3.2 Операции преобразования
- •7.3.3 Неоднозначности
- •7.5 Большие объекты
- •Void f2(t a) // вариант с контролем
- •Void f3(t a) // вариант с контролем
- •Inv() обращает саму матрицу m, а не возвращает новую, обратную m,
- •7.13 Предостережения
- •8.1 Введение
- •8.4.4 Неявная передача операций
- •8.4.5 Введение операций с помощью параметров шаблонного класса
- •8.7.1 Задание реализации с помощью параметров шаблона
- •9.1 Обработка ошибок
- •9.1.2 Другие точки зрения на особые ситуации
- •9.3.2 Производные особые ситуации
- •9.4.2 Предостережения
- •9.4.3 Исчерпание ресурса
- •9.4.4 Особые ситуации и конструкторы
- •9.5 Особые ситуации могут не быть ошибками
- •10.1 Введение
- •10.2 Вывод
- •10.2.1 Вывод встроенных типов
- •10.4.1.2 Поля вывода
- •10.4.1.4 Вывод целых
- •Istream - шаблон типа smanip, а smanip - двойник для ioss.
- •10.5.1 Закрытие потоков
- •10.5.2 Строковые потоки
- •X Целый параметр выдается в шестнадцатеричной записи;
- •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 Зависимости в рамках иерархии классов.
- •Vertical_scrollbar или с помощью одного типа scrollbar, который
- •12.2.6 Отношения использования
- •12.2.7 Отношения внутри класса
- •12.3 Компоненты
- •12.4 Интерфейсы и реализации
- •12.5 Свод правил
- •13.1 Введение
- •13.2 Конкретные типы
- •13.4 Узловые классы
- •1, 2, 6 И 7. Класс, который не удовлетворяет условию 6, походит
- •13.5.1 Информация о типе
- •13.6 Обширный интерфейс
- •13.7 Каркас области приложения
- •13.8 Интерфейсные классы
- •13.10 Управление памятью
4.3.2 Множественные заголовочные файлы
Разбиение программы в расчете на один заголовочный файл больше
подходит для небольших программ, отдельные части которых не
имеют самостоятельного назначения. Для таких программ допустимо,
что по заголовочному файлу нельзя определить, чьи описания там
находятся и по какой причине. Здесь могут помочь только комментарии.
Возможно альтернативное решение: пусть каждая часть программы
имеет свой заголовочный файл, в котором определяются средства,
предоставляемые другим частям. Теперь для каждого файла .c будет
свой файл .h, определяющий, что может предоставить первый. Каждый файл
.c будет включать как свой файл .h, так и некоторые другие файлы .h,
исходя из своих потребностей.
Попробуем использовать такую организацию программы для
калькулятора. Заметим, что функция error() нужна практически во всех
функциях программы, а сама использует только <iostream.h>. Такая
ситуация типична для функций, обрабатывающих ошибки.
Следует отделить ее от файла main.c:
// error.h: обработка ошибок
extern int no_of_errors;
extern double error(const char* s);
// error.c
#include <iostream.h>
#include "error.h"
int no_of_errors;
double error(const char* s) { /* ... */ }
При таком подходе к разбиению программы каждую пару файлов .c
и .h можно рассматривать как модуль, в котором файл .h задает
его интерфейс, а файл .c определяет его реализацию.
Таблица имен не зависит ни от каких частей калькулятора, кроме
части обработки ошибок. Теперь этот факт можно выразить
явно:
// table.h: описание таблицы имен
struct name {
char* string;
name* next;
double value;
};
extern name* look(const char* p, int ins = 0);
inline name* insert(const char* s) { return look(s,1); }
// table.h: определение таблицы имен
#include "error.h"
#include <string.h>
#include "table.h"
const int TBLSZ = 23;
name* table[TBLSZ];
name* look(const char* p, int ins) { /* ... */ }
Заметьте, что теперь описания строковых функций берутся из включаемого
файла <string.h>. Тем самым удален еще один источник ошибок.
// lex.h: описания для ввода и лексического анализа
enum token_value {
NAME, NUMBER, END,
PLUS='+', MINUS='-', MUL='*',
PRINT=';', ASSIGN='=', LP='(', RP= ')'
};
extern token_value curr_tok;
extern double number_value;
extern char name_string[256];
extern token_value get_token();
Интерфейс с лексическим анализатором достаточно запутанный. Поскольку
недостаточно соответствующих типов для лексем, пользователю
функции get_token() предоставляются те же буферы number_value
и name_string, с которыми работает сам лексический анализатор.
// lex.c: определения для ввода и лексического анализа
#include <iostream.h>
#include <ctype.h>
#include "error.h"
#include "lex.h"
token_value curr_tok;
double number_value;
char name_string[256];
token_value get_token() { /* ... */ }
Интерфейс с синтаксическим анализатором определен четко:
// syn.h: описания для синтаксического анализа и вычислений
extern double expr();
extern double term();
extern double prim();
// syn.c: определения для синтаксического анализа и вычислений
#include "error.h"
#include "lex.h"
#include "syn.h"
double prim() { /* ... */ }
double term() { /* ... */ }
double expr() { /* ... */ }
Как обычно, определение основной программы тривиально:
// main.c: основная программа
#include <iostream.h>
#include "error.h"
#include "lex.h"
#include "syn.h"
#include "table.h"
int main(int argc, char* argv[]) { /* ... */ }
Какое число заголовочных файлов следует использовать для данной
программы зависит от многих факторов. Большинство их определяется
способом обработки файлов именно в вашей системе, а не
собственно в С++. Например, если ваш редактор не может работать
одновременно с несколькими файлами, диалоговая обработка нескольких
заголовочных файлов затрудняется. Другой пример: может оказаться,
что открытие и чтение 10 файлов по 50 строк каждый занимает
существенно больше времени, чем открытие и чтение одного файла из 500
строк. В результате придется хорошенько подумать, прежде чем
разбивать небольшую программу, используя множественные заголовочные
файлы. Предостережение: обычно можно управиться с множеством, состоящим
примерно из 10 заголовочных файлов (плюс стандартные заголовочные
файлы). Если же вы будете разбивать программу на минимальные логические
единицы с заголовочными файлами (например, создавая для каждой структуры
свой заголовочный файл), то можете очень легко получить неуправляемое
множество из сотен заголовочных файлов.
