- •Предварительные замечания
 - •Структура книги
 - •Глава 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 Упражнения
 
5.4 Еще о классах
В этом разделе описаны дополнительные свойства класса. Описан
способ обеспечить доступ к частным членам в функциях, не являющихся
членами ($$5.4.1). Описано, как разрешить коллизии имен членов
($$5.4.2) и как сделать описания классов вложенными ($$5.4.3), но
при этом избежать нежелательной вложенности ($$5.4.4). Вводится понятие
статических членов (static), которые используются для представления
операций и данных, относящихся к самому классу, а не к отдельным
его объектам ($$5.4.5). Раздел завершается примером, показывающим,
как можно построить дискриминирующее (надежное) объединение ($$5.4.6).
5.4.1 Друзья
Пусть определены два класса: vector (вектор) и matrix (матрица).
Каждый из них скрывает свое представление, но дает полный набор операций
для работы с объектами его типа. Допустим, надо определить функцию,
умножающую матрицу на вектор. Для простоты предположим, что
вектор имеет четыре элемента с индексами от 0 до 3, а в матрице
четыре вектора тоже с индексами от 0 до 3. Доступ к элементам
вектора обеспечивается функцией elem(), и аналогичная функция есть
для матрицы. Можно определить глобальную функцию multiply
(умножить) следующим образом:
vector multiply(const matrix& m, const vector& v);
{
vector r;
for (int i = 0; i<3; i++) { // r[i] = m[i] * v;
r.elem(i) = 0;
for (int j = 0; j<3; j++)
r.elem(i) +=m.elem(i,j) * v.elem(j);
}
return r;
}
Это вполне естественное решение, но оно может оказаться очень
неэффективным. При каждом вызове multiply() функция elem() будет
вызываться 4*(1+4*3) раз. Если в elem() проводится настоящий
контроль границ массива, то на такой контроль будет потрачено
значительно больше времени, чем на выполнение самой функции, и в
результате она окажется непригодной для пользователей. С другой
стороны, если elem() есть некий специальный вариант доступа без
контроля, то тем самым мы засоряем интерфейс с вектором и матрицей
особой функцией доступа, которая нужна только для обхода контроля.
Если можно было бы сделать multiply членом обоих классов
vector и matrix, мы могли бы обойтись без контроля индекса при
обращении к элементу матрицы, но в то же время не вводить специальной
функции elem(). Однако, функция не может быть членом двух классов.
Надо иметь в языке возможность предоставлять функции, не являющейся
членом, право доступа к частным членам класса. Функция - не член
класса, - имеющая доступ к его закрытой части, называется другом
этого класса. Функция может стать другом класса, если в его
описании она описана как friend (друг). Например:
class matrix;
class vector {
float v[4];
// ...
friend vector multiply(const matrix&, const vector&);
};
class matrix {
vector v[4];
// ...
friend vector multiply(const matrix&, const vector&);
};
Функция-друг не имеет никаких особенностей, за исключением права
доступа к закрытой части класса. В частности, в такой функции
нельзя использовать указатель this, если только она действительно
не является членом класса. Описание friend является настоящим
описанием. Оно вводит имя функции в область видимости класса,
в котором она была описана, и при этом происходят обычные проверки
на наличие других описаний такого же имени в этой области
видимости. Описание friend может находится как в общей, так и в
частной частях класса, это не имеет значения.
Теперь можно написать функцию multiply, используя элементы
вектора и матрицы непосредственно:
vector multiply(const matrix& m, const vector& v)
{
vector r;
for (int i = 0; i<3; i++) { // r[i] = m[i] * v;
r.v[i] = 0;
for ( int j = 0; j<3; j++)
r.v[i] +=m.v[i][j] * v.v[j];
}
return r;
}
Отметим, что подобно функции-члену дружественная функция
явно описывается в описании класса, с которым дружит. Поэтому она
является неотъемлемой частью интерфейса класса наравне с
функцией-членом.
Функция-член одного класса может быть другом другого класса:
class x {
// ...
void f();
};
class y {
// ...
friend void x::f();
};
Вполне возможно, что все функции одного класса являются друзьями
другого класса. Для этого есть краткая форма записи:
class x {
friend class y;
// ...
};
В результате такого описания все функции-члены y становятся друзьями
класса x.
