- •Предисловие
- •Структура книги
- •Благодарности
- •1. Начинаем
- •1.1. Решение задачи
- •1.2. Программа на языке C++
- •1.2.1. Порядок выполнения инструкций
- •1.3. Директивы препроцессора
- •1.4. Немного о комментариях
- •1.5. Первый взгляд на ввод/вывод
- •1.5.1. Файловый ввод/вывод
- •2. Краткий обзор С++
- •2.1. Встроенный тип данных “массив”
- •2.2. Динамическое выделение памяти и указатели
- •2.3. Объектный подход
- •2.4. Объектно-ориентированный подход
- •2.5. Использование шаблонов
- •2.7. Использование пространства имен
- •2.8. Стандартный массив – это вектор
- •Часть II
- •3. Типы данных С++
- •3.1. Литералы
- •3.2. Переменные
- •3.2.1. Что такое переменная
- •3.2.2. Имя переменной
- •3.2.3. Определение объекта
- •3.3. Указатели
- •3.4. Строковые типы
- •3.4.1. Встроенный строковый тип
- •3.4.2. Класс string
- •3.5. Спецификатор const
- •3.6. Ссылочный тип
- •3.7. Тип bool
- •3.8. Перечисления
- •3.9. Тип “массив”
- •3.9.1. Многомерные массивы
- •3.9.2. Взаимосвязь массивов и указателей
- •3.10. Класс vector
- •3.11. Класс complex
- •3.12. Директива typedef
- •3.14. Класс pair
- •3.15. Типы классов
- •4. Выражения
- •4.2. Арифметические операции
- •4.3. Операции сравнения и логические операции
- •4.4. Операции присваивания
- •4.5. Операции инкремента и декремента
- •4.6. Операции с комплексными числами
- •4.7. Условное выражение
- •4.8. Оператор sizeof
- •4.9. Операторы new и delete
- •4.10. Оператор “запятая”
- •4.11. Побитовые операторы
- •4.12. Класс bitset
- •4.13. Приоритеты
- •4.14. Преобразования типов
- •4.1. Что такое выражение?
- •4.14.1. Неявное преобразование типов
- •4.14.2. Арифметические преобразования типов
- •4.14.3. Явное преобразование типов
- •4.14.4. Устаревшая форма явного преобразования
- •4.15. Пример: реализация класса Stack
- •5. Инструкции
- •5.1. Простые и составные инструкции
- •5.2. Инструкции объявления
- •5.3. Инструкция if
- •5.4. Инструкция switch
- •5.5. Инструкция цикла for
- •5.6. Инструкция while
- •5.8. Инструкция do while
- •5.8. Инструкция break
- •5.9. Инструкция continue
- •5.10. Инструкция goto
- •5.11. Пример связанного списка
- •5.11.1. Обобщенный список
- •6. Абстрактные контейнерные типы
- •6.1. Система текстового поиска
- •6.2. Вектор или список?
- •6.3. Как растет вектор?
- •6.4. Как определить последовательный контейнер?
- •6.5. Итераторы
- •6.6. Операции с последовательными контейнерами
- •6.6.1. Удаление
- •6.6.2. Присваивание и обмен
- •6.6.3. Обобщенные алгоритмы
- •6.7. Читаем текстовый файл
- •6.8. Выделяем слова в строке
- •6.9. Обрабатываем знаки препинания
- •6.10. Приводим слова к стандартной форме
- •6.11. Дополнительные операции со строками
- •6.12. Строим отображение позиций слов
- •6.12.2. Поиск и извлечение элемента отображения
- •6.12.3. Навигация по элементам отображения
- •6.12.4. Словарь
- •6.12.5. Удаление элементов map
- •6.13. Построение набора стоп-слов
- •6.13.2. Поиск элемента
- •6.13.3. Навигация по множеству
- •6.14. Окончательная программа
- •6.15. Контейнеры multimap и multiset
- •6.16. Стек
- •6.17. Очередь и очередь с приоритетами
- •6.18. Вернемся в классу iStack
- •Часть III
- •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.3.5. Значения параметров по умолчанию
- •7.3.6. Многоточие
- •7.4. Возврат значения
- •7.5. Рекурсия
- •7.6. Встроенные функции
- •7.7. Директива связывания extern "C" A
- •7.8.1. Класс для обработки параметров командной строки
- •7.9. Указатели на функции
- •7.9.1. Тип указателя на функцию
- •7.9.2. Инициализация и присваивание
- •7.9.3. Вызов
- •7.9.4. Массивы указателей на функции
- •7.9.5. Параметры и тип возврата
- •7.9.6. Указатели на функции, объявленные как extern "C"
- •8. Область видимости и время жизни
- •8.1. Область видимости
- •8.1.1. Локальная область видимости
- •8.2. Глобальные объекты и функции
- •8.2.1. Объявления и определения
- •8.2.2. Сопоставление объявлений в разных файлах
- •8.2.3. Несколько слов о заголовочных файлах
- •8.3. Локальные объекты
- •8.3.1. Автоматические объекты
- •8.3.2. Регистровые автоматические объекты
- •8.3.3. Статические локальные объекты
- •8.4. Динамически размещаемые объекты
- •8.4.2. Шаблон auto_ptr А
- •8.4.3. Динамическое создание и уничтожение массивов
- •8.4.5. Оператор размещения new А
- •8.5. Определения пространства имен А
- •8.5.1. Определения пространства имен
- •8.5.2. Оператор разрешения области видимости
- •8.5.3. Вложенные пространства имен
- •8.5.4. Определение члена пространства имен
- •8.5.5. ПОО и члены пространства имен
- •8.5.6. Безымянные пространства имен
- •8.6. Использование членов пространства имен А
- •8.6.1. Псевдонимы пространства имен
- •8.6.2. Using-объявления
- •8.6.3. Using-директивы
- •8.6.4. Стандартное пространство имен std
- •9. Перегруженные функции
- •9.1. Объявления перегруженных функций
- •9.1.1. Зачем нужно перегружать имя функции
- •9.1.2. Как перегрузить имя функции
- •9.1.3. Когда не надо перегружать имя функции
- •9.1.4. Перегрузка и область видимости A
- •9.1.5. Директива extern "C" и перегруженные функции A
- •9.1.6. Указатели на перегруженные функции A
- •9.1.7. Безопасное связывание A
- •9.2. Три шага разрешения перегрузки
- •9.3. Преобразования типов аргументов A
- •9.3.1. Подробнее о точном соответствии
- •9.3.3. Подробнее о стандартном преобразовании
- •9.3.4. Ссылки
- •9.4. Детали разрешения перегрузки функций
- •9.4.1. Функции-кандидаты
- •9.4.2. Устоявшие функции
- •9.4.3. Наилучшая из устоявших функция
- •9.4.4. Аргументы со значениями по умолчанию
- •10. Шаблоны функций
- •10.1. Определение шаблона функции
- •10.2. Конкретизация шаблона функции
- •10.3. Вывод аргументов шаблона А
- •10.4. Явное задание аргументов шаблона A
- •10.5. Модели компиляции шаблонов А
- •10.5.1. Модель компиляции с включением
- •10.5.2. Модель компиляции с разделением
- •10.5.3. Явные объявления конкретизации
- •10.6. Явная специализация шаблона А
- •10.7. Перегрузка шаблонов функций А
- •10.8. Разрешение перегрузки при конкретизации A
- •10.9. Разрешение имен в определениях шаблонов А
- •10.10. Пространства имен и шаблоны функций А
- •10.11. Пример шаблона функции
- •11. Обработка исключений
- •11.1. Возбуждение исключения
- •11.2. try-блок
- •11.3. Перехват исключений
- •11.3.1. Объекты-исключения
- •11.3.2. Раскрутка стека
- •11.3.3. Повторное возбуждение исключения
- •11.3.4. Перехват всех исключений
- •11.4. Спецификации исключений
- •11.4.1. Спецификации исключений и указатели на функции
- •11.5. Исключения и вопросы проектирования
- •12. Обобщенные алгоритмы
- •12.1. Краткий обзор
- •12.2. Использование обобщенных алгоритмов
- •12.3. Объекты-функции
- •12.3.1. Предопределенные объекты-функции
- •12.3.2. Арифметические объекты-функции
- •12.3.3. Сравнительные объекты-функции
- •12.3.4. Логические объекты-функции
- •12.3.5. Адаптеры функций для объектов-функций
- •12.3.6. Реализация объекта-функции
- •12.4. Еще раз об итераторах
- •12.4.1. Итераторы вставки
- •12.4.2. Обратные итераторы
- •12.4.3. Потоковые итераторы
- •12.4.4. Итератор istream_iterator
- •12.4.5. Итератор ostream_iterator
- •12.4.6. Пять категорий итераторов
- •12.5. Обобщенные алгоритмы
- •12.5.1. Алгоритмы поиска
- •12.5.2. Алгоритмы сортировки и упорядочения
- •12.5.3. Алгоритмы удаления и подстановки
- •12.5.4. Алгоритмы перестановки
- •12.5.5. Численные алгоритмы
- •12.5.6. Алгоритмы генерирования и модификации
- •12.5.7. Алгоритмы сравнения
- •12.5.8. Алгоритмы работы с множествами
- •12.5.9. Алгоритмы работы с хипом
- •12.6.1. Операция list_merge()
- •12.6.2. Операция list::remove()
- •12.6.3. Операция list::remove_if()
- •12.6.4. Операция list::reverse()
- •12.6.5. Операция list::sort()
- •12.6.6. Операция list::splice()
- •12.6.7. Операция list::unique()
- •Часть IV
- •13. Классы
- •13.1. Определение класса
- •13.1.1. Данные-члены
- •13.1.2. Функции-члены
- •13.1.3. Доступ к членам
- •13.1.4. Друзья
- •13.1.5. Объявление и определение класса
- •13.2. Объекты классов
- •13.3. Функции-члены класса
- •13.3.1. Когда использовать встроенные функции-члены
- •13.3.2. Доступ к членам класса
- •13.3.3. Закрытые и открытые функции-члены
- •13.3.4. Специальные функции-члены
- •13.3.5. Функции-члены со спецификаторами const и volatile
- •13.3.6. Объявление mutable
- •13.4. Неявный указатель this
- •13.4.1. Когда использовать указатель this
- •13.5. Статические члены класса
- •13.5.1. Статические функции-члены
- •13.6. Указатель на член класса
- •13.6.1. Тип члена класса
- •13.6.2. Работа с указателями на члены класса
- •13.6.3. Указатели на статические члены класса
- •13.7. Объединение – класс, экономящий память
- •13.8. Битовое поле – член, экономящий память
- •13.9. Область видимости класса A
- •13.9.1. Разрешение имен в области видимости класса
- •13.10. Вложенные классы A
- •13.11. Классы как члены пространства имен A
- •13.12. Локальные классы A
- •14.1. Инициализация класса
- •14.2. Конструктор класса
- •14.2.1. Конструктор по умолчанию
- •14.2.2. Ограничение прав на создание объекта
- •14.2.3. Копирующий конструктор
- •14.3. Деструктор класса
- •14.3.1. Явный вызов деструктора
- •14.3.2. Опасность увеличения размера программы
- •14.4. Массивы и векторы объектов
- •14.4.1. Инициализация массива, распределенного из хипа A
- •14.4.2. Вектор объектов
- •14.5. Список инициализации членов
- •14.6. Почленная инициализация A
- •14.6.1. Инициализация члена, являющегося объектом класса
- •14.7. Почленное присваивание A
- •14.8. Соображения эффективности A
- •15.1. Перегрузка операторов
- •15.1.1. Члены и не члены класса
- •15.1.2. Имена перегруженных операторов
- •15.1.3. Разработка перегруженных операторов
- •15.2. Друзья
- •15.3. Оператор =
- •15.4. Оператор взятия индекса
- •15.5. Оператор вызова функции
- •15.6. Оператор “стрелка”
- •15.7. Операторы инкремента и декремента
- •15.8. Операторы new и delete
- •15.8.1. Операторы new[ ] и delete [ ]
- •15.8.2. Оператор размещения new() и оператор delete()
- •15.9. Определенные пользователем преобразования
- •15.9.1. Конвертеры
- •15.9.2. Конструктор как конвертер
- •15.10. Выбор преобразования A
- •15.10.1. Еще раз о разрешении перегрузки функций
- •15.10.2. Функции-кандидаты
- •15.11. Разрешение перегрузки и функции-члены A
- •15.11.1. Объявления перегруженных функций-членов
- •15.11.2. Функции-кандидаты
- •15.11.3. Устоявшие функции
- •15.12. Разрешение перегрузки и операторы A
- •15.12.1. Операторные функции-кандидаты
- •15.12.2. Устоявшие функции
- •15.12.3. Неоднозначность
- •16. Шаблоны классов
- •16.1. Определение шаблона класса
- •16.1.1. Определения шаблонов классов Queue и QueueItem
- •16.2. Конкретизация шаблона класса
- •16.2.1. Аргументы шаблона для параметров-констант
- •16.3. Функции-члены шаблонов классов
- •16.3.1. Функции-члены шаблонов Queue и QueueItem
- •16.4. Объявления друзей в шаблонах классов
- •16.4.1. Объявления друзей в шаблонах Queue и QueueItem
- •16.5. Статические члены шаблонов класса
- •16.6. Вложенные типы шаблонов классов
- •16.7. Шаблоны-члены
- •16.8. Шаблоны классов и модель компиляции A
- •16.8.1. Модель компиляции с включением
- •16.8.2. Модель компиляции с разделением
- •16.8.3. Явные объявления конкретизации
- •16.9. Специализации шаблонов классов A
- •16.10. Частичные специализации шаблонов классов A
- •16.11. Разрешение имен в шаблонах классов A
- •16.12. Пространства имен и шаблоны классов
- •16.13. Шаблон класса Array
- •Часть V
- •17. Наследование и подтипизация классов
- •17.1. Определение иерархии классов
- •17.1.1. Объектно-ориентированное проектирование
- •17.2. Идентификация членов иерархии
- •17.2.1. Определение базового класса
- •17.2.2. Определение производных классов
- •17.2.3. Резюме
- •17.3. Доступ к членам базового класса
- •17.4. Конструирование базового и производного классов
- •17.4.1. Конструктор базового класса
- •17.4.2. Конструктор производного класса
- •17.4.3. Альтернативная иерархия классов
- •17.4.4. Отложенное обнаружение ошибок
- •17.4.5. Деструкторы
- •17.5.1. Виртуальный ввод/вывод
- •17.5.2. Чисто виртуальные функции
- •17.5.3. Статический вызов виртуальной функции
- •17.5.4. Виртуальные функции и аргументы по умолчанию
- •17.5.5. Виртуальные деструкторы
- •17.5.6. Виртуальная функция eval()
- •17.5.7. Почти виртуальный оператор new
- •17.5.8. Виртуальные функции, конструкторы и деструкторы
- •17.6. Почленная инициализация и присваивание A
- •17.7. Управляющий класс UserQuery
- •17.7.1. Определение класса UserQuery
- •17.8. Соберем все вместе
- •18.1. Готовим сцену
- •18.2. Множественное наследование
- •18.3. Открытое, закрытое и защищенное наследование
- •18.3.1. Наследование и композиция
- •18.3.2. Открытие отдельных членов
- •18.3.3. Защищенное наследование
- •18.3.4. Композиция объектов
- •18.4. Область видимости класса и наследование
- •18.5. Виртуальное наследование A
- •18.5.1. Объявление виртуального базового класса
- •18.5.2. Специальная семантика инициализации
- •18.5.3. Порядок вызова конструкторов и деструкторов
- •18.5.4. Видимость членов виртуального базового класса
- •18.6.2. Порождение класса отсортированного массива
- •18.6.3. Класс массива с множественным наследованием
- •19. Применение наследования в C++
- •19.1. Идентификация типов во время выполнения
- •19.1.1. Оператор dynamic_cast
- •19.1.2. Оператор typeid
- •19.1.3. Класс type_info
- •19.2. Исключения и наследование
- •19.2.1. Исключения, определенные как иерархии классов
- •19.2.2. Возбуждение исключения типа класса
- •19.2.3. Обработка исключения типа класса
- •19.2.4. Объекты-исключения и виртуальные функции
- •19.2.5. Раскрутка стека и вызов деструкторов
- •19.2.6. Спецификации исключений
- •19.2.7. Конструкторы и функциональные try-блоки
- •19.3. Разрешение перегрузки и наследование A
- •19.3.1. Функции-кандидаты
- •19.3.3. Наилучшая из устоявших функций
- •20. Библиотека iostream
- •20.1. Оператор вывода <<
- •20.2. Ввод
- •20.2.1. Строковый ввод
- •20.3. Дополнительные операторы ввода/вывода
- •20.4. Перегрузка оператора вывода
- •20.5. Перегрузка оператора ввода
- •20.6. Файловый ввод/вывод
- •20.7. Состояния потока
- •20.8. Строковые потоки
- •20.9. Состояние формата
- •20.10. Сильно типизированная библиотека
- •accumulate()
- •adjacent_difference()
- •adjacent_find()
- •binary_search()
- •copy()
- •copy_backward()
- •count_if()
- •equal()
- •equal_range()
- •fill()
- •find()
- •find_if()
- •find_end()
- •find_first_of()
- •generate()
- •generate_n()
- •includes()
- •inplace_merge()
- •iter_swap()
- •lexicographical_compare()
- •max_element()
- •merge()
- •next_permutation()
- •nth_element()
- •partial_sort()
- •partial_sort_copy()
- •partition()
- •prev_permutation()
- •random_shuffle()
- •remove()
- •remove_if()
- •remove_copy_if()
- •replace_copy()
- •replace_if()
- •replace_copy_if()
- •reverse_copy()
- •rotate()
- •search_n()
- •set_difference()
- •set_intersection()
- •set_union()
- •sort()
- •stable_partition()
- •swap()
- •swap_ranges()
- •transform()
- •unique_copy()
- •upper_bound()
- •Алгоритмы для работы с хипом
- •make_heap()
- •pop_heap()
- •push_heap()
- •sort_heap()
С++ для начинающих |
3 |
Предисловие
Между выходом второго и третьего издания “С++ для начинающих” произошло довольно много событий. Одним из самых значительных стало появление международного стандарта. Он не только добавил в язык С++ новые возможности, среди которых обработка исключений, идентификация типов во время выполнения, пространство имен, встроенный булевский тип данных, новый синтаксис приведения типов, но также существенно изменил и расширил имеющиеся – шаблоны, механизм классов, поддерживающий объектную и объектно-ориентированную парадигму программирования, вложенные типы и разрешение перегруженных функций. Еще более важным событием стало включение в состав стандарта С++ обширной библиотеки, содержащей, в частности, то, что ранее называлось Standard Template Library (STL). В эту стандартную библиотеку входят новый тип string, последовательные и ассоциативные контейнеры, такие, как vector, list, map, set, и обширный набор обобщенных алгоритмов, которые могут применяться ко всем этим типам данных. Появилось не просто много нового материала, нуждающегося в описании, но фактически изменился сам способ мышления при программировании на С++. Короче говоря, можно считать, что С++ изобретен заново, поэтому третье издание нашей книги “C++ для начинающих” полностью переработано.
В третьем издании не только коренным образом поменялся наш подход к С++, изменились и авторы. Прежде всего, авторский коллектив удвоился и стал интернациональным, хотя корни его по-прежнему на североамериканском континенте: Стен (Stan) американец, а Жози (Josйe) канадка. Двойное авторство отражает деление сообщества программистов С++ на две части: Стен в настоящее время занимается разработкой приложений на C++ в области трехмерной графики и анимации для Walt Disney Feature Animation, а Жози принимает участие в развитии самого языка С++, являясь председателем рабочей группы по ядру языка в комитете по стандартизации и одним из разработчиков компилятора С++ в IBM Canada Laboratory.
Стен работает над С++ с 1984 года. Он был одним из членов первоначальной команды, трудившейся в Bell Laboratories под руководством Бьерна Страуструпа (Bjarne Stroustrup), изобретателя языка. Стен принимал участие в разработке cfront, оригинальной реализации С, с версии 1.1 в 1986 году до версии 3.0, и возглавлял проект при работе над версиями 2.1 и 3.0. После этого он работал под началом Страуструпа над проектом, посвященным исследованиям объектной модели программной среды разработки на C++.
Жози – член команды, работающей над компилятором С++ в IBM Canada Laboratory на протяжении восьми лет. С 1990 года она входит в состав комитета по стандартизации. Три года она была вице-президентом комитета и четыре года – председателем рабочей группы по ядру языка.
Третье издание “C++ для начинающих” существенно переработано, что отражает не только развитие и расширение языка, но и изменения во взглядах и опыте авторов книги.
Структура книги
“C++ для начинающих” содержит обстоятельное введение в международный стандарт С++. Мы включили в название книги слова “для начинающих” потому, что последовательно придерживались учебного подхода к описанию языка С++; однако название не предполагает упрощенного или облегченного изложения материала. Такие аспекты программирования, как обработка исключений, контейнерные типы, объектно-ориентированный подход и т.п.,
С++ для начинающих |
4 |
представлены в книге в контексте решения конкретных задач. Правила языка, например разрешение перегруженных функций или преобразования типов в объектно- ориентированном программировании, рассматриваются столь подробно, что во вводном курсе это может показаться неуместным. Но мы уверены, что такое освещение необходимо для практического применения языка. Материал книги не нужно стараться усвоить “за один проход”: мы предполагаем, что читатель будет периодически возвращаться к ранее прочитанным разделам. Если некоторые из них покажутся вам слишком трудными или просто скучными, отложите их на время. (Подозрительные разделы мы помечали значком А.)
Читатель может не знать язык С, хотя некоторое знакомство с каким-либо современным структурным языком программирования было бы полезно. Мы писали книгу, которая стала бы первым учебником по С++, а не первым учебником по программированию! Чтобы не делать предположений о начальном уровне подготовки, мы начинаем с определения базовых терминов. В первых главах описываются базовые концепции, такие, как переменные и циклы, и для некоторых читателей изложение может показаться слишком примитивным, но вскоре оно становится более углубленным.
Основное достоинство С++ заключается в том, что он поддерживает новые способы решения программистских задач. Поэтому чтобы научиться эффективно использовать С++, недостаточно просто выучить новые синтаксис и семантику. Для более глубокого усвоения в книге рассматриваются разнообразные сквозные примеры. Эти примеры используются как для того, чтобы представить разные средства языка, так и для того, чтобы объяснить, зачем эти средства нужны. Изучая возможности языка в контексте реального примера, мы понимаем, чем полезно то или иное средство, как и где его можно применить при решении задач из реальной жизни. Кроме того, на примерах проще продемонстрировать понятия языка, которые еще детально не рассматривались и излагаются лишь в последующих главах.
В начальных главах примеры содержат простые варианты использования базовых понятий С++. Их цель – показать, как можно программировать на С++, не углубляясь в детали проектирования и реализации.
Главы 1 и 2 представляют собой полное введение в язык С++ и его обзор. Назначение первой части – как можно быстрее познакомить читателя с понятиями и средствами данного языка, а также основными принципами написания программ.
По окончании этой части у вас должно сложиться некоторое общее представление о возможностях С++, но вместе с тем вполне может остаться ощущение, что вы совсем ничего толком не понимаете. Все нормально: упорядочению ваших знаний как раз и посвящены остальные части книги!
В главе 1 представлены базовые элементы языка: встроенные типы данных, переменные, выражения, инструкции и функции. Мы увидим минимальную законченную программу на С++, обсудим вопросы компиляции, коснемся препроцессора и поддержки ввода/вывода. В этой главе читатель найдет ряд простых, но законченных С++ программ, которые можно откомпилировать и выполнить. Глава 2 посвящена механизму классов и тому, как с его помощью поддержаны парадигмы объектного и объектно-ориентированного программирования. Оба эти подхода иллюстрируются развитием реализации массива как абстрактного типа. Кроме того, приводится краткая информация о шаблонах, пространствах имен, обработке исключений и о поддержке стандартной библиотекой общих контейнерных типов и методов обобщенного (generic) программирования. Материал в этой главе излагается весьма стремительно, и потому некоторым читателям она может показаться трудной. Мы
С++ для начинающих |
5 |
рекомендуем таким читателям просмотреть вторую главу “по диагонали” и вернуться к ней впоследствии.
Фундаментальной особенностью С++ является возможность расширять язык, определяя новые типы данных, которые могут использоваться с тем же удобством и гибкостью, что и встроенные. Первым шагом к овладению этим искусством является знание базового языка. Часть II (главы 3-6) посвящена рассмотрению языка на этом уровне.
В главе 3 представлены встроенные и составные типы, предопределенные в языке, а также типы string, complex и vector из стандартной библиотеки С++. Эти типы составляют основные “кирпичики”, из которых строятся все программы. В главе 4 детально освещаются выражения языка – арифметические, условные, присваивания. Инструкции языка, которые являются мельчайшими независимыми единицами С++ программы, представлены в главе 5. Контейнерные типы данных стали предметом главы 6. Вместо простого перечисления совокупности поддерживаемых ими операций, мы иллюстрируем операции на примере построения системы текстового поиска.
Главы 7-12 (часть III) посвящены процедурно-ориентированному программированию на С++. В главе 7 представлен механизм функций. Функция инкапсулирует набор операций, составляющих единую задачу, как, например, print(). (Круглые скобки после имени говорят о том, что мы имеем дело с функцией.) Такие понятия, как область видимости и время жизни переменных, рассматриваются в главе 8. Обзор механизма функций продолжен в главе 9: речь пойдет о перегрузке функций, которая позволяет присвоить одно и то же имя нескольким функциям, выполняющим похожие, но по-разному реализованные операции. Например, можно определить целый набор функций print() для печати данных разных типов. В главе 10 представлено понятие шаблона функции и приведены примеры его использования. Шаблон функции предназначен для автоматической генерации потенциально бесконечного множества экземпляров функций, отличающихся только типами данных.
С++ поддерживает обработку исключений. Об исключении говорят, когда в программе возникает нестандартная ситуация, такая, например, как нехватка свободной памяти. В том месте программы, где это происходит, возбуждается исключение, то есть о проблеме ставится в известность вызывающая программа. Какая-то другая функция в программе должна обработать исключение, то есть как-то отреагировать на него. Материал об исключениях разбит на две части. В главе 11 описан основной синтаксис и приведен простой пример, иллюстрирующий возбуждение и обработку исключений типа класса. Поскольку
реальные исключения в программах обычно являются объектами некоторой иерархии классов, то мы вернемся к этому вопросу в главе 19, после того как узнаем, что такое объектно-ориентированное программирование.
В главе 12 представлена обширная коллекция обобщенных алгоритмов стандартной библиотеки и способы их применения к контейнерным типам из главы 6, а также к массивам встроенных типов. Эта глава начинается разбором примера построения программы с использованием обобщенных алгоритмов. Итераторы, введенные в главе 6, обсуждаются более детально в главе 12, поскольку именно они являются связующим звеном между обобщенными алгоритмами и контейнерными типами. Также мы вводим и иллюстрируем на примерах понятие объекта-функции. Объекты-функции позволяют задавать альтернативную семантику операций, используемых в обобщенных алгоритмах, – скажем, операций сравнения на равенство или по величине. Детальное описание самих алгоритмов и примеры их использования приводятся в приложении.
С++ для начинающих |
6 |
Главы 13-16 (часть IV) посвящены объектному программированию, то есть использованию механизма классов для создания абстрактных типов данных. С помощью типов данных, описывающих конкретную предметную область, язык С++ позволяет программистам сосредоточиться на решении основной задачи и тратить меньше усилий на второстепенные.
Фундаментальные для приложения типы данных могут быть реализованы один раз и использованы многократно, что дает программисту возможность не думать о деталях реализации главной задачи. Инкапсуляция данных значительно упрощает последующее сопровождение и модификацию программы.
Вглаве 13 основное внимание мы уделим общим вопросам механизма классов: как определить класс, что такое сокрытие информации (разделение открытого интерфейса и скрытой реализации), как определять экземпляры класса и манипулировать ими. Мы также коснемся областей видимости класса, вложенных классов и классов как членов пространства имен.
Вглаве 14 детально исследуются средства, имеющиеся в С++ для инициализации и уничтожения объектов класса и для присваивания им значений. Для этих целей служат специальные функции-члены, называемые конструкторами, деструкторами и копирующими операторами присваивания. Мы рассмотрим вопрос о почленной инициализации и копировании, а также специальную оптимизацию для этого случая,
которая получила название именованное возвращаемое значение.
Вглаве 15 мы рассмотрим перегрузку операторов применительно к классам. Сначала мы остановимся на общих понятиях и вопросах проектирования, а затем перейдем к рассмотрению конкретных операторов, таких, как присваивание, доступ по индексу, вызов функции, а также операторов new и delete, специфичных для классов.
Будет представлено понятие дружественного класса, имеющего особые права доступа, и объяснено, зачем нужны друзья. Будут рассмотрены и определенные пользователями преобразования типов, стоящие за ними концепции и примеры использования. Кроме того, приводятся правила разрешения функций при перегрузке, иллюстрируемые примерами программного кода.
Шаблоны классов – тема главы 16. Шаблон класса можно рассматривать как алгоритм создания экземпляра класса, в котором параметры шаблона подлежат замене на конкретные значения типов или констант. Скажем, в шаблоне класса vector параметризован тип его элементов. В классе для представления некоторого буфера можно параметризовать не только тип размещаемых элементов, но и размер самого буфера. При разработке сложных механизмов, например в области распределенной обработки данных, могут быть параметризованы практически все интерфейсы: межпроцессной коммуникации, адресации, синхронизации. В главе 16 мы расскажем, как определить шаблон класса, как создать экземпляр класса, подставляя в шаблон конкретные значения, как определить члены шаблона класса (функции-члены, статические члены и вложенные типы) и как следует организовывать программу, в которой используются шаблоны классов. Заканчивается эта глава содержательным примером шаблона класса.
Объектно-ориентированному программированию (ООП) и его поддержке в С++ посвящены главы 17-20 (часть IV). В главе 17 описываются средства поддержки базовых концепций ООП – наследования и позднего связывания. В ООП между классами, имеющими общие черты поведения, устанавливаются отношения родитель/потомок (или тип/подтип). Вместо того чтобы повторно реализовывать общие характеристики, класс-потомок может унаследовать их от класса-родителя. В класс-потомок (подтип) следует добавить только те
С++ для начинающих |
7 |
детали, которые отличают его от родителя. Например, мы можем определить родительский класс Employee (работник) и двух его потомков: TemporaryEmpl (временный работник) и Manager (начальник), которые наследуют все поведение Employee. В них самих реализованы только специфичные для подтипа особенности. Второй аспект ООП, полиморфизм, позволяет родительскому классу представлять любого из своих наследников. Скажем, класс Employee может адресовать не только объект своего типа, но и объект типа TemporaryEmpl или Manager. Позднее связывание – это способность разрешения операций во время выполнения, то есть выбора нужной операции в зависимости от реального типа объекта. В С++ это реализуется с помощью механизма виртуальных функций.
Итак, в главе 17 представлены базовые черты ООП. В ней мы продолжим начатую в главе 6 работу над системой текстового поиска – спроектируем и реализуем иерархию классов запросов Query.
Вглаве 18 разбираются более сложные случаи наследования – множественное и виртуальное. Шаблон класса из главы 16 получает дальнейшее развитие и становится трехуровневой иерархией с множественным и виртуальным наследованием.
Вглаве 19 представлено понятие идентификации типа во время выполнения (RTTI – run time type identification). RTTI позволяет программе запросить у полиморфного объекта класса информацию о его типе во время выполнения. Например, мы можем спросить у объекта Employee, действительно ли он представляет собой объект типа Manager. Кроме того, в
главе 19 мы вернемся к исключениям и рассмотрим иерархию классов исключений стандартной библиотеки, приводя примеры построения и использования своей собственной иерархии классов исключений. В этой главе рассматривается также вопрос о разрешении перегруженных функций в случае наследования классов.
В главе 20 подробно рассматривается использование библиотеки ввода/вывода iostream. Здесь мы на примерах покажем основные возможности ввода и вывода, расскажем, как определить свои операторы ввода и вывода для класса, как проверять состояние потока и изменять его, как форматировать данные. Библиотека ввода/вывода представляет собой иерархию классов с множественным и виртуальным наследованием.
Завершается книга приложением, где все обобщенные алгоритмы приведены в алфавитном порядке, с примерами их использования.
При написании книги зачастую приходится оставлять в стороне множество вопросов, которые представляются не менее важными, чем вошедшие в книгу. Отдельные аспекты языка – детальное описание того, как работают конструкторы, в каких случаях создаются временные объекты, общие вопросы эффективности – не вписывались во вводный курс. Однако эти аспекты имеют огромное значение при проектировании реальных приложений. Перед тем как взяться за “C++ для начинающих”, Стен написал книгу “Inside the C++ Object Model” [LIPPMAN96a], в которой освещаются именно эти вопросы. В тех местах “C++ для начинающих”, где читателю может потребоваться более детальная информация, даются ссылки на разделы указанной книги.
Некоторые части стандартной библиотеки С++ были сознательно исключены из рассмотрения, в частности поддержка национальных языков и численные методы. Стандартная библиотека С++ очень обширна, и все ее аспекты невозможно осветить в одном учебнике. Материал по отсутствующим вопросам вы можете найти в книгах, приведенных в списке литературы ([MUSSER96] и [STRUOSTRUP97u]). Наверняка вскоре выйдет еще немало книг, освещающих различные аспекты стандартной библиотеки С++.