- •«Московский государственный технический университет гражданской авиации»
- •Лабораторная работа № 9 Наследование с использованием виртуальных функций
- •1.1. Цель лабораторной работы
- •1.2. Теоретические сведения Включение и наследование классов
- •Наследование
- •Полиморфизм виртуальных функций
- •Чистая виртуальные функции. Абстрактный класс.
- •Virtual void Func () { }
- •Void f ( );
- •Int Func (char*);
- •Void f ( );
- •Статические члены класса
- •Int main () {
- •Указатель this
- •1.3 Задание на выполнение лабораторной работы
- •1.4 Порядок выполнения
- •1.5 Методические указания
- •1.6 Содержание отчета
- •1.7 Контрольные вопросы
- •1.8 Варианты задания
- •2 Лабораторная работа № 10 Обработка типовых исключений. Исключения типа стандартных данных, исключения - классы.
- •Цель лабораторной работы
- •2.2. Теоретические сведения Общие сведения об исключениях
- •Механизм обработки исключений (мои)
- •Перехват исключений
- •Void f1() {
- •Void f2() {
- •Int main () {
- •Int main () {
- •Int main () {
- •Indeterminacy
- •Исключения, функции и раскручивание стека
- •Int main () {
- •Непойманные исключения и обработчики всех типов исключений catch-all
- •Int main () {
- •Обработчики всех типов исключений
- •Int main (){
- •Int main () {
- •Список исключений функции
- •Int doSomething () throw (double, const char*)
- •Исключения в конструкторах и деструкторах
- •Vector V (I);
- •Int main () {
- •Исключения в перегрузке операций
- •Int& ArrayInt :: operator [] (const int index){
- •Int& ArrayInt :: operator [](const int index) {
- •Void assert (int expression);
- •Int& ArrayInt :: operator [] (const int index) {
- •Классы-Исключения
- •Int getLength () {return 4;}
- •Int main () {
- •В случае иерархии классов.
- •Интерфейсный класс std :: exception
- •Int main () {
- •2.3 Задание на выполнение лабораторной работы
- •2.4 Порядок выполнения работы
- •2.5. Контрольные вопросы
- •2.6. Варианты заданий лабораторной работы
- •3. Лабораторная работа № 11 Разработка программ обработки символьной информации.
- •3.1. Цель лабораторной работы
- •3.2. Теоретические сведения
- •Int main () {
- •Int main (){
- •Конструкторы и присваивание строк
- •Допустимые для объектов класса string операции:
- •3.3 Задание на выполнение лабораторной работы
- •3.4 Порядок выполнения работы
- •3.5. Методические указания
- •Istream& getline (istream& is, string& str, char delim);
- •Istream& getline (istream& is, string& str);
- •Int main () {
- •Int main () {
- •3.6 Контрольные вопросы
- •3.7 Варианты заданий лабораторной работы
- •1.1. Цель лабораторной работы 3
- •1.2. Теоретические сведения 3
Исключения, функции и раскручивание стека
Рассмотрим, как взаимодействуют функции во время обработки исключений в языке С++.
Выше было показано, что операторы throw вовсе не обязаны находиться непосредственно в блоке try, благодаря выполнению такой операции, как «раскручивание стека». Это предоставляет нам необходимую гибкость в разделении общего потока выполнения кода программы и обработки исключений.
Продемонстрируем это еще раз, вынеся генерацию исключения и вычисление квадратного корня в отдельную функцию.
#include <cmath> // для sqrt ()
#include <iostream>
// Пользовательская функция вычисления квадратного корня
double mySqrt (double a) {
// Если пользователь ввел отрицательное число, то выбрасываем
//исключение
if (a < 0.0) // выбрасывается исключение типа const char*
throw " Cannot take sqrt of negative number ";
return sqrt(a); //если не возникла исключительная ситуация, корень
// вычисляется функция возвращает его значение
}
Int main () {
std::cout << " Enter a number: ";
double a;
std::cin >> a;
try { // ищем исключения, которые выбрасываются в блоке try, и
// отправляем их для обработки в блок(и) catch
double d = mySqrt (a);
std::cout << "The sqrt of " << a << " is " << d << '\n';
}
catch (const char* exception) //обработка исключений типа const char*
{ std::cerr << "Error: " << exception << std::endl;
}
return 0;
}
Здесь поместили генерацию исключения и операцию вычисления квадратного корня в отдельную функцию mySqrt (). Затем эта функция вызывается в блоке try.
Убедимся, что всё работает, как нужно:
Enter a number: -3
Error: Cannot take sqrt of negative number
Работает! Рассмотрим ход выполнения программы.
Во-первых, при генерации исключения компилятор определяет, можно ли сразу же (мгновенно) обработать это исключение (для этого нужно, чтобы исключение выбрасывалось внутри блока try). Поскольку точка выполнения не находится внутри блока try, то и обработать исключение немедленно не получится.
Таким образом, выполнение функции mySqrt () приостанавливается, и компилятор определяет, может ли программный код, который вызывает mySqrt (так называемый, caller), обработать это исключение.
Если нет, то компилятор завершает выполнение caller-а и переходит на уровень выше — к caller-у, который вызывает текущего caller-а, чтобы проверить, сможет ли тот обработать исключение. И так последовательно до тех пор, пока не будет найден соответствующий обработчик исключения, или пока функция main () не завершит свое выполнение без обработки исключения. Этот процесс называется раскручиванием стека.
Рассмотрим детально, как это относится к нашей программе. Сначала компилятор проверяет, генерируется ли исключение внутри блока try. В нашем случае — нет, поэтому стек начинает раскручиваться. При этом функция mySqrt () завершает свою работу, и точка выполнения перемещается обратно в функцию main ().
Теперь компилятор проверяет снова, находимся ли мы внутри блока try. Поскольку вызов функции mySqrt () был выполнен из блока try, то компилятор начинает искать соответствующий обработчик catch. Он находит обработчик типа const char*, и исключение обрабатывается блоком catch внутри main ().
Другими словами, блок try ловит исключения не только внутри себя, но и внутри функций, которые вызываются в этом блоке try.
Самое интересное здесь в том, что mySqrt () выбрасывает исключение, но обработка этой проблему в mySqrt () отсутствует. Это, по сути, делегирование ответственности за обработку исключения caller-у.
В конечном счете, это позволяет отделить функционал mySqrt () от кода обработки исключений, который можно разместить в других (менее важных) частях кода.
Когда исключение обработано, выполнение кода продолжается как обычно, начиная с конца блока catch (в котором это исключение было обработано). К тому времени, когда точка выполнения возвращается обратно в функцию main (), исключение уже было сгенерировано и обработано. Функция main () выполняется так, как если бы этого исключения не было вообще!
Раскручивание стека является очень полезным механизмом, так как позволяет в функциях не обрабатывать исключения, если это нецелесообразно. Операция раскручивания стека выполняется до тех пор, пока не будет обнаружен соответствующий блок catch! Таким образом, можно решать, где следует обрабатывать исключения.
