- •Предисловие
- •Глава 1. Основные понятия
- •1.1. Элементы языка программирования
- •1.2. Процесс создания программы
- •1.3. Первая программа
- •1.4. Состав программы
- •Глава 2. Средства разработки на C++
- •2.1. Системы Turbo C++ 3.0/Borland C++ 3.1
- •2.2. Система C++ Builder
- •Глава 3. Работа с числовыми данными
- •3.1. Целые типы
- •3.2. Числа с плавающей точкой
- •3.3. Ввод и вывод чисел
- •3.4. Логический тип и логические операции
- •3.5. Математические функции
- •Глава 4. Операторы. Ключевые слова
- •4.1. Операторы
- •4.2. Приоритеты операторов
- •4.3. Ключевые слова
- •4.4. Структура программы
- •4.5. Константы
- •Задачи - . Простейшие вычисления
- •Глава 5. Управление и циклы
- •5.1. Условный оператор
- •5.2. Операторы цикла
- •5.3. Переключатель
- •5.4. Операторы break и continue
- •Задачи -. Выбор и циклы
- •Глава 6. Массивы
- •6.1. Одномерные массивы
- •6.2. Двумерные массивы
- •Задачи -. Одно- и двумерные массивы
- •Глава 7. Функции
- •7.1. Определение функции
- •7.2. Формальные параметры и фактические аргументы
- •7.3. Автоматические и статические переменные
- •7.4. Прототипы функций
- •7.5. Массивы как аргументы функций
- •7.6. Внешние переменные
- •7.7. Рекурсия
- •7.8. Перегруженные имена функций
- •7.9. Аргументы функций по умолчанию
- •Задачи -. Функции
- •Глава 8. Символы и строки
- •8.1. Символы
- •8.2. Строки символов
- •Задачи -. Символы и строки
- •Глава 9. Препроцессор
- •9.1. Директивы препроцессора
- •9.2. Макросы
- •Задачи -. Макросы
- •Глава 10. Указатели и ссылки
- •10.1. Указатели и адреса
- •10.2. Указатели и массивы
- •10.3. Адресная арифметика
- •10.4. Символьные указатели
- •10.5. Массивы указателей
- •10.6. Указатели на функции
- •10.7. Ссылки
- •10.8. Операторы new и delete
- •Задачи -. Указатели и ссылки
- •Глава 11. О файлах и командной строке
- •11.1. Знакомство с файлами
- •11.2. Командная строка
- •11.3. Перенаправление стандартного ввода и вывода на файл
- •11.4. Аргументы командной строки
- •Задачи -. Файлы и командная строка
- •Глава 12. Работа с экраном дисплея
- •12.1. Текстовый режим
- •12.2. Графический режим
- •Задачи -. Работа с экраном
- •Глава 13. Внутреннее представление чисел
- •13.1. Двоичная система счисления
- •13.2. Беззнаковые целые
- •13.3. Двоичный дополнительный код
- •13.4. Двоичный код с избытком
- •13.5. Побитовые операторы
- •13.6. Дробные числа в двоичной системе
- •13.7. Внутреннее представление плавающих типов
- •13.8. Преобразование типов
- •Задачи -. Побитовые операторы
- •Глава 14. Структуры, перечисления, объединения
- •14.1. Объявление структур
- •14.2. Структуры и функции
- •14.3. Указатели на структуры
- •14.4. Массивы структур
- •14.5. Перечисления
- •14.6. Объединения
- •14.7. Битовые поля
- •14.8. О бинарных файлах
- •Задачи -. Структуры
- •Глава 15. Классы
- •15.1. Структуры в C++. Инкапсуляция
- •15.2. Встроенные функции
- •15.3. Классы. Скрытие данных
- •15.4. Конструкторы
- •15.5. Статические члены класса
- •15.6. Друзья класса
- •15.7. Копирование объектов класса
- •15.8. Управление доступом
- •15.9. Ссылка на себя
- •15.10. Деструкторы
- •Задачи -. Работа с классами
- •Глава 16. Программы из нескольких файлов
- •16.1. Работа с проектами
- •16.2. Область действия имен
- •16.3. Заголовочные файлы
- •16.4. Пространства имен
- •Задачи -. Работа со стеком
- •Глава 17. Перегрузка операторов
- •17.1. Правила перегрузки операторов
- •Задачи -. Перегрузка операторов
- •Глава 18. Конструктор копирования и оператор присваивания
- •18.1. Проблемы при копировании
- •Задачи -. Конструктор копирования
- •Глава 19. Ввод и вывод
- •19.1. Вывод
- •19.2. Ввод
- •19.3. Ввод и вывод определяемых пользователем типов
- •19.4. Работа с файлами
- •Глава 20. Взаимоотношения классов
- •20.1. Объекты как члены класса
- •20.2. Конструкторы встроенных типов
- •20.3. Наследование
- •20.4. Виртуальные функции
- •20.5. Абстрактные классы
- •20.6. Совместимость типов
- •20.7. Множественное наследование
- •Задачи -. Наследование классов
- •Глава 21. Шаблоны, исключения
- •21.1. Шаблоны
- •21.2. Шаблоны функций
- •21.3. Классы и шаблоны
- •21.4. Обработка исключений
- •21.5. Стандартная библиотека шаблонов
- •Литература
- •Предметный указатель
314
for(i = 0; i < y.SizeArr(); i++) // Заполнение массива y y[i] = rand();
cout << Rus("Количество элементов в y: ") << y.SizeArr(); cout << Rus(", максимальное из y: ") << y.GetMax(); cin.get();
return 0;
}
При одном из запусков программа напечатала:
Количество элементов в x: 64, максимальное из x: 32635 Количество элементов в y: 20, максимальное из y: 30486
21.4. Обработка исключений
Исключение – это особая ситуация, возникающая в ходе работы программы. Встроенными особыми ситуациями являются «деление на нуль», «конец файла», «переполнение при вычислении». В языке C++ любое состояние, достигнутое в процессе выполнения программы, можно заранее определить как особую ситуацию (исключение) и предусмотреть действия, которые нужно выполнить при её возникновении.
Для реализации механизма обработки исключений в языке C++ есть три ключевых слова:
try (пробовать, пытаться, испытывать), catch (ловить, обнаруживать),
throw (бросать, посылать).
Эти ключевые слова позволяют выделить контролируемый блок, зафиксировать исключение и назначить обработчик исключения. Схема обработки исключений имеет вид:
try{ |
// Контролируемый блок |
ОПЕРАТОРЫ |
// Обычные операторы |
throw ВЫР; |
// Передача управления обработчику исключений |
ОПЕРАТОРЫ |
|
}
catch(ТИП_ИСКЛЮЧЕНИЯ ИМЯ){ // Обработчик исключений ОПЕРАТОРЫ
}
Программист должен предусмотреть передачу управления оператору throw при возникновении исключения. Оператор throw прерывает естественный ход работы программы и передает управление в тот блок catch, у которого ТИП_ИСКЛЮЧЕНИЯ соответствует типу ВЫР, при этом объект ИМЯ инициализируется значением ВЫР.
315
В приводимой ниже программе демонстрируется обработка исключений в задаче о нахождении наибольшего общего делителя двух целых чисел x и y.
Программа 68. Расчет НОД
Справедливы следующие свойства НОД двух чисел: Nod(x, y) = x, если х = у;
Nod(x, y) = Nod(y, x - y), если х > у, Nod(x, y) = Nod(y, x);
если х <= 0, или у <= 0, то Nod не определён.
Исключительными ситуациями при расчете НОД является равенство нулю или отрицательное значение одного из чисел.
Для передачи информации из точки, где возникло исключение в обработчик исключений, введём специальный класс Except, членами которого будут две целые переменные m, n, хранящие значение х и у, и строка mess с сообщением о характере особой ситуации.
//Файл Exeption.cpp #include <iostream.h>
struct Except{ |
// Класс для информации об исключении |
int m, n; |
// Числа |
char* mess; |
// Описание исключения |
Except(int a, int b, char* msg) // Конструктор {m = a; n = b; mess = msg;}
}; |
|
|
int Nod(int x, int y) |
|
|
{ |
|
|
if(x == 0 || y == 0) |
throw Except(x, y, "Zero!"); |
|
if(x < 0) |
|
throw Except(x, y, "Negative argument 1."); |
if(y < 0) |
|
throw Except(x, y, "Negative argument 2."); |
if(x == y) |
return x; |
|
if(x < y) |
return Nod(y, x); |
return Nod(y, x - y);
}
void main()
{
try{
cout << "\nNod(66, 44) = " << Nod(66, 44)<< '\n'; cout << "\nNod(0, 7) = " << Nod(0, 7)<< '\n'; cout << "\nNod(-12, 8) = " << Nod(-12, 8)<< '\n';
316
}
// Обработчик исключений. В d содержится информация об исключении catch(Except d){
cerr << d.mess << " x = " << d.m << ", y = " << d.n <<'\n';
}
cin.get();
}
Здесь после throw стоит вызов конструктора класса Except, который создаёт безымянный объект, инициализированный значением аргументов Nod и текстом сообщения. Этот объект будет передан в блок catch и использован для инициализации параметра d, тем самым информация об исключении становится доступной в обработчике исключений. Обработка исключения состоит в выводе в поток для ошибок cerr сведений о возникшей проблеме, передаваемых через объект d.
Программа выдает:
Nod(66, 44) = 22
Zero! x = 0, y = 7
Здесь исключение возникает при вычислении Nod(0, 7). Оператор throw прерывает выполнение функции Nod и передает управление в блок catch. Причем отыскивается тот из нескольких возможых блоков catch, которые могут стоять за блоком try, у которого тип объектаисключения соответствует генерируемому типу исключения в операторе throw. Оператор вида
catch(…){ |
// Обработчик исключений |
ИНСТРУКЦИИ |
|
} |
|
перехватывает исключения любых типов.
21.5. Стандартная библиотека шаблонов
Для обработки данных используются различные структуры данных: массивы, списки, стеки, очереди, множества и т.д. Такая структура данных, как массив, встроена в C++, так же, как и в другие языки программирования. В стандарт C++ входит стандартная библиотека шаблонов STL (Standard Template Library), предназначенная для создания и обработки различных структур данных. В STL содержатся три основные сущности: контейнеры, алгоритмы и итераторы.
317
Контейнер организует хранение данных. Контейнеры STL реализованы в виде шаблонов классов, поэтому обеспечивают хранение как величин базовых типов int, float,…, так и объекты классов. Необходимость в наличии специальных контейнеров вызвана тем, что обычный массив бывает неэффективен, например, часто приходится создавать массивы с запасом, хотя в большинстве случаев память не расходуется полностью.
Контейнеры бывают последовательные и ассоциативные. Последовательными контейнерами являются, например, векторы (vector), списки (list). Ассоциативные контейнеры – это, например, множества (set), отображения или ассоциативные массивы (map). Контейнеры имеют методы, позволяющие работать с ними. Перечислим некоторые:
size() – возвращает текущее число элементов в контейнере; empty() – возвращает true, если контейнер пуст;
max_size() – размер самого большого возможного контейнера; resize() – изменяет размер контейнера (только вектора, списка).
Алгоритмы – это независимые шаблонные функции, не являющиеся членами контейнерных классов, поэтому их можно применять как к классам-контейнерам, так и к обычным массивам. Вот некоторые
алгоритмы: |
|
|
|
|
|
find() – |
находит |
первое |
вхождение |
значения |
в |
|
последовательность; |
|
|
|
|
count() – |
подсчитывает количество вхождений данного значения |
||||
|
в последовательность; |
|
|
|
|
equal() – |
возвращает |
true, |
если |
элементы |
двух |
|
последовательностей попарно равны; |
|
|||
search() – |
находит первое вхождение последовательности как |
||||
|
подпоследовательности; |
|
|
|
|
sort() – |
сортирует последовательность в указном порядке. |
|
Итераторы – это обобщение понятия указателей. Итераторы ссылаются на элементы контейнеров и обеспечивают к ним доступ. К итераторам можно применять оператор ++, после выполнения которого итератор будет ссылаться на следующий элемент контейнера. Переход от элемента к элементу называется итерацией. Значение элемента по итератору получается оператором *. В STL итератор представляет собой объект класса iterator.
Для разных типов контейнеров используются свои итераторы. Существует три типа итераторов.
Прямой итератор может проходить по контейнеру только в прямом направлении, к нему применяется оператор ++.
318
Двунаправленный итератор может передвигаться в обоих направлениях и реагирует на операторы ++ и --.
Итератор со случайным доступом может двигаться в обоих направлениях и перескакивать на любой элемент контейнера.
Контейнеры имеют методы, возвращающие итераторы. Приведем для примера два таких метода:
begin() – возвращает итератор на начало контейнера;
end() – возвращает итератор на последнюю позицию в контейнере.
В следующей программе приводится пример использования небольшой части возможностей STL.
Программа 69. Использование шаблона векторов
Термин вектор применяется в STL к динамическим массивам. Шаблон класса векторов vector реализует оператор [] доступа к элементу и оператор присваивания. Вектора из элементов конкретного типа создаются инструкциями вида:
vector <int> Numb(N0);
где Numb – имя создаваемого вектора, N0 – число элементов вектора.
В программе создается вектор с числом элементов N0, затем его размер изменяется до N. Вектор заполняется случайными числами, копируется в другой вектор, который затем сортируется.
// Файл STLVctr.cpp |
|
#include <iostream> |
|
#include <vector> |
|
#include <algorithm> |
|
#include <conio.h> |
|
using namespace std; |
|
const int Max = 1000; |
// Максимальное значение элемента массива |
const int N0 = 10; |
// Первоначальный размер массива |
void main() |
|
{ |
|
vector <int> Numb(N0); |
// Numb - массив из N0 элементов типа int |
int N; |
// Количество чисел в массиве |
cout << "Input the count of numbers "; // Приглашение ввести размер cin >> N; // Ввод нового размера массива
// size() возвращает текущий размер
if (Numb.size() != N) // Если текущий размер не равен новому, Numb.resize(N); // устанавливаем новый размер
// resize(N) изменяет размер массива на новый, равный N cout << "\nThe Source array\n"; // Исходный массив
|
319 |
for(int i = 0; i < Numb.size(); i++) |
// Заполнение массива случайными |
cout << (Numb[i] = rand() % Max) << ' '; // числами и вывод |
|
vector <int> NumbSort(N); |
// Еще один массив |
NumbSort = Numb; // Новому массиву присваиваем значение старого sort(NumbSort.begin(), NumbSort.end()); // Сортировка массива
//begin() возвращает итератор на первый элемент,
//end() - на последний
cout << "\n The Sorted array\n"; |
// Отсортированный массив |
for(int i = 0; i < NumbSort.size(); i++) |
// Вывод отсортированного |
cout << NumbSort[i] << ' '; |
// массива |
getch(); |
|
}
Далее приведен диалог с программой.
Input the count of numbers 12 The Source array
346 130 982 90 656 117 595 415 948 126 4 558 The Sorted array
4 90 117 126 130 346 415 558 595 656 948 982
Таким образом, STL позволяет легко делать ряд полезных вещей, которые недоступны для базовых типов данных, например, присваивание массивов, их эффективную сортировку и т.п.