- •Содержание
- •ВВЕДЕНИЕ
- •1.ОБЪЕКТНО-ОРИЕНТИРОВАННЫЙ ПОДХОД
- •2. ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ
- •2.1. Абстрактные типы данных
- •2.2. Базовые принципы объектно-ориентированного программирования
- •2.3. Основные достоинства языка С++
- •2.4. Особенности языка С++
- •2.4.1. Ключевые слова
- •2.4.2. Константы и переменные
- •2.4.3. Операции
- •2.4.4. Типы данных
- •2.4.5. Передача аргументов функции по умолчанию
- •2.5.1. Объект cin
- •2.5.2. Объект cout
- •2.5.3. Манипуляторы
- •3.1. Объекты
- •3.2. Понятие класса
- •3.3. Конструктор копирования
- •3.4. Конструктор explicit
- •3.5. Указатель this
- •3.6. Встроенные функции (спецификатор inline)
- •3.7. Организация внешнего доступа к локальным компонентам класса (спецификатор friend)
- •3.8. Вложенные классы
- •3.9. Static-члены (данные) класса
- •3.10. Компоненты-функции static и const
- •3.11. Proxi-классы
- •3.12. Ссылки
- •3.12.1. Параметры ссылки
- •3.12.2. Независимые ссылки
- •3.13. Пространства имен
- •3.13.3. Ключевое слово using как объявление
- •3.13.4. Псевдоним пространства имен
- •3.14. Практические приемы ограничения числа объектов класса
- •4. НАСЛЕДОВАНИЕ
- •4.1.1. Конструкторы и деструкторы при наследовании
- •4.2. Виртуальные функции
- •4.3. Абстрактные классы
- •4.4. Виртуальные деструкторы
- •4.6. Виртуальное наследование
- •5.2. Перегрузка операторов
- •5.2.2. Перегрузка унарного оператора
- •5.2.3. Дружественная функция operator
- •5.2.4. Особенности перегрузки операции =
- •5.2.5. Перегрузка оператора []
- •5.2.6. Перегрузка оператора ()
- •5.2.7. Перегрузка оператора ->
- •5.2.8. Перегрузка операторов new и delete
- •5.3. Преобразование типа
- •5.3.1. Явные преобразования типов
- •6. ШАБЛОНЫ
- •6.1. Параметризированные классы
- •6.2. Передача в шаблон класса дополнительных параметров
- •6.3. Шаблоны функций
- •6.4. Совместное использование шаблонов и наследования
- •6.5. Шаблоны класса и friend-функции
- •6.6. Некоторые примеры использования шаблона класса
- •6.6.1. Реализация smart-указателя
- •6.6.2. Задание значений параметров класса по умолчанию
- •7.2. Состояние потока
- •7.3. Строковые потоки
- •7.4. Организация работы с файлами
- •7.5. Организация файла последовательного доступа
- •7.6. Создание файла произвольного доступа
- •7.7. Основные функции классов ios, istream, ostream
- •8. ИСКЛЮЧЕНИЯ В С++
- •8.2. Перенаправление исключительных ситуаций
- •8.3. Исключительная ситуация, генерируемая оператором new
- •8.6. Спецификации исключительных ситуаций
- •8.7. Задание собственного неожиданного обработчика
- •9. СТАНДАРТНАЯ БИБЛИОТЕКА ШАБЛОНОВ (STL)
- •9.3. Категории итераторов
- •9.4. Операции с итераторами
- •9.5. Контейнеры последовательностей
- •9.5.2. Контейнер последовательностей list
- •9.5.3. Контейнер последовательностей deque
- •9.6. Ассоциативные контейнеры
- •9.6.1. Ассоциативный контейнер multiset
- •9.6.2. Ассоциативный контейнер set
- •9.6.3. Ассоциативный контейнер multimap
- •9.7.1. Адаптер stack
- •9.7.2. Адаптер queue
- •9.7.3. Адаптер priority_queue
- •9.8. Алгоритмы
- •9.8.1. Алгоритмы сортировки sort, partial_sort, sort_heap
- •9.8.2. Алгоритмы поиска find, find_if, find_end, binary_search
- •9.8.3. Алгоритмы fill, fill_n, generate и generate_n
- •9.8.4. Алгоритмы equal, mismatch и lexicographical_compare
- •9.8.6. Алгоритмы работы с множествами
- •9.8.7. Алгоритмы swap, iter_swap и swap_ranges
- •9.8.8. Алгоритмы copy, copy_backward, merge, unique и reverse
- •10. ПРИМЕРЫ РЕАЛИЗАЦИИ КОНТЕЙНЕРНЫХ КЛАССОВ
- •10.1. Связанные списки
- •10.1.1. Реализация односвязного списка
- •10.2. Реализация бинарного дерева
- •11. ПРОГРАММИРОВАНИЕ ДЛЯ WINDOWS
- •11.1. Система, управляемая сообщениями
- •11.2. Управление графическим выводом
- •11.3. Контекст устройства
- •11.3.1. Экран
- •11.3.2. Принтер
- •11.3.3. Объект в памяти
- •11.3.4. Информационный контекст
- •11.4. Архитектура, управляемая событиями
- •11.5. Исходный текст программы
- •11.7. Некоторые новые типы данных
- •11.8. Венгерская нотация
- •11.9. Точка входа программы
- •11.11. Создание окна
- •11.12. Цикл обработки сообщений
- •11.13. Оконная процедура
- •11.14. Обработка сообщений
- •11.15. Обработка сообщений функцией DefWindowProc
- •11.16. Синхронные и асинхронные сообщения
- •11.17. Еще один метод получения описателя контекста устройства
- •11.19. Полосы прокрутки
- •Литература
}
}
Эту проблему можно легко устранить, если поместить указатель на новый динамический объект:
void f() { A obj;
|
. . . |
} |
throw new A; |
Р |
|
При этом необходимо решить вопрос о необходимости удаления динамически |
созданного объекта исключения (например в блоке catch). В противном случае возможны утечки памяти.
ключительную ситуацию сначала на более низком уровнеГвложенностиУ блока try, а затем передать ее на более высокий уровень для продолжения обработки. Для того чтобы сделать это, нужно использовать throw без аргументов. В этом
8.2. Перенаправление исключительных ситуаций |
|
Иногда возникает положение, при котором необходимо обработатьИ |
ис- |
случае исключительная ситуация будет перен правленаБк следующему подхо- дящему обработчику (подходящий обработч не ищется ниже в текущем спи-
ске − сразу осуществляется поиск на более высо ом уровне). Приводимый ниже
пример демонстрирует организацию такой п ред чи. Программа содержит вло- |
|||||||||
|
|
|
|
|
|
|
|
|
а |
женный блок try и соответствующий блок catch. Сначала происходит первичная |
|||||||||
|
|
|
|
|
|
|
|
ик |
|
обработка, затем исключительная си уация п ренаправляется на более высокий |
|||||||||
уровень для дальнейшей обрабо ки. |
е |
|
|||||||
#include<iostream> |
|
т |
|
|
|||||
using namespace std; |
|
|
|
||||||
|
|
|
|
|
|
|
|
||
void func(int i) |
|
о |
|
|
|
||||
{ try{ |
|
|
и |
|
|
|
|
||
|
|
|
|
|
|
|
|
||
|
if(i) throw "Error"; |
|
|
|
|
||||
} |
|
|
л |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
catch(char *s) { |
|
|
|
|
|
|
|||
|
|
б |
выполняется первый обработчик"<<endl; |
||||||
|
cout<<s<<"- |
||||||||
|
throw; |
|
|
|
|
|
|
|
|
} |
и |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Б |
|
|
|
|
|
|
|
|
int main() { try{
func(1);
}
catch(char *s) {
174
cout<<s<<"- выполняется второй обработчик"<<endl;
}
}
Результат выполнения программы: Error - выполняется первый обработчик Error - выполняется второй обработчик
Если ключевое слово trow используется вне блока catch, то автоматически будет вызвана функция terminate(), которая по умолчанию завершает програм-
му. |
Р |
|
И |
|
8.3. Исключительная ситуация, генерируемая оператором new |
|
Следует отметить, что некоторые компиляторы поддерживают генерацию |
исключений в случае ошибки выделения памяти посредством оператора new, в частности исключения типа bad_alloc. Оно может быть перехвачено и необхо-
димым образом обработано. Ниже в программе рассмотрен пример генерации и |
||||||||||
обработки исключительной ситуаций bad alloc. УИскусственно вызывается |
||||||||||
ошибка выделения памяти и перехватывается исключительная ситуация. |
||||||||||
|
#include <new> |
|
|
|
|
Г |
||||
|
|
|
|
|
Б |
|||||
|
#include <iostream> |
|
|
|
||||||
|
using namespace std; |
|
|
а |
||||||
|
int main() |
|
|
|
|
|||||
|
{ |
double *p; |
|
|
|
к |
|
|||
|
|
try{ |
|
|
|
е |
|
|
||
|
|
|
|
|
|
|
|
|
||
|
|
} |
while(1) p=new double[100]; // генерация ошибки выделения памяти |
|||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
catch(bad alloc exept) { |
|
|
// обработчик xalloc |
|||||
|
|
|
|
|
|
т |
|
|
|
|
|
|
|
cout<<"В зникло исключение"<<exept.what()<<endl; |
|||||||
|
|
} |
|
|
о |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
||
|
} |
|
|
и |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
В случае если компилятором не генерируется исключение bad_alloc, то |
|||||||||
можно это исключение создать искусственно: |
||||||||||
|
б |
|
|
|
|
|
|
|
||
|
#include <new> |
|
|
|
|
|
||||
и |
|
|
|
|
|
|
|
|
||
Б |
#include <iostream> |
|
|
|
|
|||||
using namespace std; |
|
|
|
|
||||||
int main() |
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
||||
|
{ |
double *p; |
|
|
|
|
|
|
||
|
|
bad_alloc exept; |
|
|
|
|
|
|||
|
|
try{ |
|
|
|
|
|
|
|
|
|
|
|
if(!(p=new double[100000000])) // память не выделена p==NULL |
|||||||
|
|
|
throw exept; |
|
|
// генерация ошибки выделения памяти |
||||
|
|
|
|
|
|
|
|
|
|
175 |
} |
|
catch(bad_alloc exept) { |
// обработчик bad_alloc |
cout<<"Возникло исключение "<<exept.what()<<endl; |
|
} |
|
return 0; |
|
} |
|
Результатом работы программы будет сообщение: |
|
Возникло исключение bad |
allocation |
|
Р |
Оператор new появился в языке C++ еще до того, как был введен меха- |
низм обработки исключительных ситуаций, поэтому первоначально в случае ошибки выделения памяти этот оператор просто возвращал NULL.ИЕсли требу-
ется, чтобы new работал именно так, надо вызвать функцию set_new handler() с
параметром 0. Кроме того, с помощью set_new_handler() можно задать функ-
цию, которая будет вызываться в случае ошибки выделения памяти. Функция
set_new_handler (в заголовочном файле new) принимает в качестве аргумента
указатель на функцию, которая не принимает никаких аргументов и возвращает |
|||||||||||
void. |
|
|
|
|
|
|
|
|
|
|
У |
|
|
|
|
|
|
|
|
|
Г |
||
#include<new> |
|
|
|
|
|
|
|||||
|
|
|
|
|
|
Б |
|
||||
#include<iostream> |
|
|
|
|
|
|
|||||
using namespace std; |
|
|
|
|
|
|
|||||
|
|
|
|
а |
|
||||||
void newhandler( ) |
|
|
|
|
|
||||||
{ |
cout << "The new_handler is called: "; |
|
|||||||||
|
throw bad_alloc( ); |
|
|
|
к |
|
|
||||
|
|
|
е |
|
|
|
|||||
} |
return; |
|
|
|
|
|
|
|
|
||
|
|
|
|
|
т |
|
|
|
|
||
int main( ) |
|
|
|
|
|
|
|
||||
{ |
char* ptr; |
|
|
|
|
|
|
|
|||
|
|
о |
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
||
|
set_new_handler (newhandler); |
|
|
|
|
|
|||||
|
try { |
|
|
и |
|
|
|
|
|
|
|
|
|
л |
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
||
|
ptr = new char[~size_t(0)/2]; |
|
|
|
|
|
|||||
|
delete[ ] ptr; |
|
|
|
|
|
|
|
|
||
|
|
б |
|
|
|
|
|
|
|
|
|
|
и |
|
|
|
|
|
|
|
|
|
|
Б |
|
|
|
|
|
|
|
|
|
|
}
catch( bad_alloc &ba) { cout << ba.what( ) << endl;
}
return 0;
}
Результатом работы программы является
The new_handler is called: bad allocation
176
В слассе new также определена функция _set_new_handler, аргументом которой является указатель на функцию, возвращающую значение типа int и получающую аргумент типа size_t, указывающий размер требуемой памяти:
#include <new> #include <iostream> using namespace std;
int error_alloc( size_t ) // size_t unsigned integer результат sizeof operator. { cout << "ошибка выделения памяти" <<endl;
return 0;
} |
Р |
int main( ) |
|
{ |
_set_new_handler( error_alloc ); |
|
|
|
|
И |
|
int *p = new int[10000000000]; |
|
|
|
|
||
return 0; |
|
|
|
|
У |
|
} |
|
|
|
|
||
|
|
|
Г |
|
||
Результатом работы функции является: |
|
|||||
ошибка выделения памяти |
|
|
Б |
|
|
|
|
|
|
|
|
||
В случае, если память не выделяется и не задается никакой функции- |
||||||
аргумента для set_new_handler, опер тор new генерирует исключение bad_alloc. |
||||||
|
а |
|
|
|
||
8.4. Генерация исклю ний в |
онструкторах |
|
||||
|
к |
|
|
|
|
|
Механизм обработки исключительных ситуаций очень удобен для обра- |
||||||
ботки ошибок, возникающихчев конструкторах. Так как конструктор не возвра- |
ходится искать альтернативу. В этом случае наилучшим решением является ге- нерация и обраб тка исключительной ситуации. При генерации исключения
щает значения, то с ве с венно нельзя возвратить некий код ошибки и при-
моменту лы ивызваны конструкторы базовых классов, то будет обеспечен и вызов соответствующих деструкторов. Рассмотрим на примере генерацию ис- ключ тельной ситуации внутри конструктора. Пусть имеется класс В, произ-
внутри конструкторапроцесс создания объекта прекращается. Если к этому
водный от класса А и содержащий в качестве компоненты-данного объект клас- |
||||
|
б |
|
|
|
са local. В конструкторе класса В генерируется исключительная ситуация. |
||||
и |
|
|
|
|
Б |
#include<iostream> |
|
||
using namespace std; |
|
|||
class local |
|
|
|
|
|
|
|
|
|
|
{ public: |
|
|
|
|
local() |
{ |
cout<<"Constructor of local"<<endl; |
} |
|
~local() |
{ |
cout<<"Destructor of local"<<endl; |
} |
|
}; |
|
|
|
|
|
|
|
177 |