Главная страница
Навигация по странице:

  • Контейнерные классы

  • Понятие исключительной ситуации

  • Механизм обработки исключений

  • Результатом выполнения этой программы будет вывод сообщений

  • Неперехваченные исключения

  • Исключения в конструкторах

  • Исключения в деструкторах

  • Курс ООП в С презентация. ООП в с++(полный курс). Объекты и классы


    Скачать 1.76 Mb.
    НазваниеОбъекты и классы
    АнкорКурс ООП в С презентация
    Дата21.02.2022
    Размер1.76 Mb.
    Формат файлаppt
    Имя файлаООП в с++(полный курс).ppt
    ТипДокументы
    #368655
    страница26 из 26
    1   ...   18   19   20   21   22   23   24   25   26

    Контейнерные классы


    int main()
    {
    const int N = 5;
    int a1[N] = {1,2,3,4,5};
    int a2[N] = {3,4,5,6,7};
    typedef set SetS;//определяем тип множество с элементами int
    //создаем множество A и инициализируем его элементами массива а1
    SetS A(a1, a1 + N);
    //создаем множество B и инициализируем его элементами массива а2
    SetS B(a2, a2 + N);
    //печать множеств с помощью функции print(), описанной выше
    print(A); print(B);
    //множество для пересечения A и В
    SetS prod;
    //множество для объединения A и В
    SetS sum;

    Контейнерные классы


    //пересечение
    //inserter() – итератор, который добавляет новый
    //элемент в произвольное место контейнера
    set_intersection(A.begin(), A.end(), B.begin(), B.end(),inserter(prod, prod.begin()));
    print(prod); //печать пересечения
    //объединение
    set_union(A.begin(). A.end(), B.begin(),
    B.end(),inserter (sum, sum.begin()));
    print(sum); //печать объединения
    //включение
    if (includes(A.begin(). A.end(), prod.begin(),
    prod.end())) cout << "Yes" < else cout <<"No"<< endl;
    return 0;
    }

    Контейнерные классы


    Словарь (map) можно представить себе как своего рода таблицу из двух столбцов, в первом из которых хранятся объекты, содержащие ключи, а во втором — объекты, содержащие значения.
    И в множествах, и в словарях все ключи являются уникальными (только одно значение соответствует ключу). Мультимножества (multiset) и мультисловари (multimap) аналогичны своим родственным контейнерам, но в них одному ключу может соответствовать несколько значений.
    В определении класса map используется тип pair, который описан в заголовочном файле . Шаблон pair имеет два параметра, представляющих собой типы элементов пары. Первый элемент пары имеет имя first, второй – second. В этом же файле определены шаблонные операции ==, !=, <, >, <=, >= для двух объектов типа pair.
    Шаблон словаря имеет три параметра: тип ключа, тип элемента и тип функционального объекта, определяющего отношение "меньше".

    Контейнерные классы


    #include
    #include
    #include "person.h"
    using namespace std;
    typedef multimap tmap;
    void main()
    {
    tmap m1;
    tmap::iterator mi1;
    int n;
    cout<<"\nn-?";
    cin>>n;
    person a;
    for(int i=0;i { cout<<"?"; cin>>a;
    m1.insert(make_pair(i,a)); } //вставка элемента в словарь
    //печать словаря с помощью функции print(), определенной выше
    print("M1:",m1);
    }


    Понятие исключительной ситуации
    При выполнении операторов программы может возникнуть ошибочная ситуация (деление на 0, обращение к элементу массива с несуществующим индексом и т. п.). В этом случае программа может предпринять одно из следующих действий:
      прервать выполнение программы;
      возвратить код ошибки;
      вывести сообщение об ошибке и вернуть программе некоторое значение, которое позволит ей продолжить работу.

      Для решения таких проблем в С++ были введены средства генерации и обработки исключений. Исключительная ситуация, или исключение – это возникновение непредвиденного или аварийного события, которое может порождаться некорректным использованием аппаратуры.
      Исключения позволяют логически разделить вычислительный процесс на две части – обнаружение аварийной ситуации и ее обработка.
      Другое достоинство исключений состоит в том, что для передачи информации об ошибке в вызывающую функцию не требуется применять возвращаемое значение, параметры или глобальные переменные, поэтому интерфейс функций не раздувается. Это особенно важно, например, для конструкторов, которые по синтаксису не могут возвращать значение

    Синтаксис исключений
    Исключение может генерироваться только в контролируемом блоке:
    try {…} //контролируемый блок
    Все функции, прямо или косвенно вызываемые из try-блока, также принадлежат контролируемому блоку.
    Генерация (порождение) исключения происходит по ключевому слову throw, которое употребляется либо с параметром, либо без него:
    throw [выражение ]; //генерация исключения
    Тип выражения, стоящего после throw, определяет тип порождаемого исключения. При генерации исключения выполнение текущего блока прекращается, и происходит поиск соответствующего обработчика и передача ему управления. Как правило, исключение генерируется не непосредственно в try-блоке, а в функциях, прямо или косвенно в него вложенных.


    Обработчики исключений начинаются с ключевого слова catch, за которым в скобках следует тип обрабатываемого исключения. Они должны располагаться непосредственно за try-блоком. Можно записать один или несколько обработчиков в соответствии с типами обрабатываемых исключений.
    Существует три формы записи:
      catch(тип имя) {тело обработчика}
      catch(тип) {тело обработчика}
      catch(...) {тело обработчика}

      Первая форма применяется, когда имя параметра используется в теле обработчика для выполнения каких-либо действий – например, вывода информации об исключении.
      Вторая форма не предполагает использования информации об исключении, играет роль только его тип. Многоточие вместо параметра обозначает, что обработчик перехватывает все исключения. Так как обработчики просматриваются в том порядке, в котором они записаны, обработчик третьего типа следует помещать после всех остальных.
      Таким образом, для того, чтобы определить исключительную ситуацию, надо:

      выделить контролируемый блок;
      предусмотреть генерацию исключений в этом блоке;
      разместить обработчики исключений после try-блока.


    try //контролируемый блок
    {

    if (ошибка) throw E(); //генерация исключения

    }
    catch (H) //обработка исключения
    {

    }
    В этом пример обработчик вызывается, если:
      E и Н одного типа,
      Н – базовый класс Е (с наследованием public),
      Е и Н – указатели или ссылки и для них выполняется 1 или 2.


    Механизм обработки исключений
    Обработка исключения начинается с появления ошибки. Функция, в которой она возникла, генерирует исключение (throw с параметром, определяющим вид исключения). Параметр может быть константой, переменной или объектом и используется для передачи информации об исключении его обработчику.
    Отыскивается соответствующий обработчик исключения (catch с таким же параметром, как у throw) и ему передается управление.
    Если обработчик исключения не найден, вызывается стандартная функция terminate, которая вызывает функцию abort, аварийно завершающую текущий процесс. Можно установить собственную функцию завершения процесса.
    Когда с помощью throw генерируется исключение, функции библиотеки C++ выполняют следующие действия:
      создают копию параметра throw в виде статического объекта, который существует до тех пор, пока исключение не будет обработано;

      в поисках подходящего обработчика раскручивают стек, вызывая деструкторы локальных объектов, выходящих из области действия;
      передают объект и управление обработчику, имеющему параметр, совместимый по типу с этим объектом.
      Раскручиванием стека называется процесс освобождения памяти из-под локальных переменных и возврата управления вызывающей функции. Когда функция завершается, происходит естественное раскручивание стека. Тот же самый механизм используется и при обработке исключений.

    Обработчик считается найденным, если тип объекта, указанного после throw:
      тот же, что и указанный в параметре catch (параметр может быть записан в форме Т, const T, T& или const T&, где Т— тип исключения);
      является производным от указанного в параметре catch (если наследование производилось с ключом доступа public);
      является указателем, который может быть преобразован по стандартным правилам преобразования указателей к типу указателя в параметре catch.

      Таким образом, обработчики производных классов следует размещать до обработчиков базовых, поскольку в противном случае им никогда не будет передано управление. Обработчик указателя типа void автоматически скрывает указатель любого другого типа, поэтому его также следует размещать после обработчиков указателей конкретного типа.

    //демонстрационная программа
    class A //демонстрационный класс
    {
    public:
    A(){cout<<"Constructor of A\n";} //конструктор без параметров
    A(){cout<<"Destructor of A\n";} //деструктор
    };
    void f1()
    {
    A a; //создали объект класса А
    throw 1; //генерируется исключение типа int
    }
    int main()
    {
    try //контролируемый блок
    {
    f1(); //выход по исключительной ситуации throw 1
    }
    //обработчик исключительной ситуации
    catch(int){ cout<<"catch of int";}
    return 0;
    }


    Результатом выполнения этой программы будет вывод сообщений:
    Constructor of A
    Destructor of A (!!!)
    catch of int
    Здесь надо обратить внимание на то, что после порождения исключения был вызван деструктор локального объекта(!!!), хотя управление из функции f1 было передано обработчику, находящемуся в функции main


    Неперехваченные исключения
    Если исключение сгенерировано, но не перехвачено, вызывается стандартная функция terminate(), по умолчанию эта функция вызывает функцию abort(). Результатом выполнения функции abort()будет окно с сообщением об аварийном завершении программы.
    Вызов функции abort()можно заменить вызовом своего обработчика с помощью функции set_terminate().
    void other_abort()
    {
    cerr<<"\nProgram is terminated";
    exit(1);
    }
    int main()
    {
    set_terminate(other_abort); //замена функции abort()
    //обработчиком other_abort()

    }


    Классы исключений
    Средствами С++ можно генерировать исключения любого встроенного типа, а также создавать специальные классы исключений и использовать в throw либо объекты этих классов, либо анонимные экземпляры.
    Использование собственных классов исключений предпочтительнее применения стандартных типов данных.
    class MathError //базовый класс обработки ошибок
    {
    virtual void ErrorProc(){…}; //обработка ошибки
    };
    class Overflow : public MathError //класс ошибки переполнения
    {
    virtual void ErrorProc(){…}; //обработка ошибки
    };
    class ZeroDevide : public MathError //класс ошибки деление на 0
    {
    virtual void ErrorProc(){…}; //обработка ошибки
    };



    try
    {

    //генерируется исключение класса ZeroDevide
    if (деление на 0) throw ZeroDevide();

    //генерируется исключение класса Owerflow
    if (переполнение) throw Owerflow();

    }
    catch (MathError& me)
    {
    me.ErrorProc();
    }
    Единственный обработчик catch принимает объект базового класса и, на этапе выполнения будет обрабатывать как исключения типа MathError, так и любого производного типа. Благодаря полиморфизму, каждый раз будет вызываться версия метода ErrorProc(), соответствующая данному типу исключения.


    Спецификации исключений
    В заголовке функции можно задать список типов исключений, которые она может прямо или косвенно порождать. Этот список приводится в конце заголовка и предваряется ключевым словом throw.
    void Func(int a) throw (ex_l, ex_2);
    Такое объявление означает, что функция Func может сгенерировать только исключения ex_l, ex_2 и исключения, являющиеся производными от этих типов. Заголовок является интерфейсом функции, поэтому такое объявление дает пользователям функции определенные гарантии. Это очень важно при использовании библиотечных функций, так как определения функций в этом случае не всегда доступны.
    Если функция сгенерирует исключение, не соответствующее спецификации исключений, то система вызовет обработчик unexpected(), который может попытаться сгенерировать свое исключение, и если оно не будет противоречить спецификации, то продолжится поиск подходящего обработчика, в противном случае вызывается функция terminate().
    Вместо функции unexpected () можно установить собственную функцию, для этого нужно воспользоваться функцией set_unexpected().
    Если спецификация исключений задана в виде throw(), это означает, что функция вообще не генерирует исключений.


    Исключения в конструкторах
    Исключения предоставляют единственную возможность передать информацию об ошибке, случившейся в процессе создания нового объекта.
    //класс вектор
    class Vect
    {
    private:
    int* p; // указатель на массив целых чисел, составляющих
    // вектор
    char size; //размер вектора
    public:
    Vect(char); //конструктор с параметром
    Vect(){delete [] p;} //деструктор
    int& operator [] (int i) //операция []
    {return p[i];}
    void Print(); //печать вектора
    };


    //реализация методов класса Vect
    Vect::Vect(char n)
    {
    size = n;
    p = new int[n]; //выделение памяти
    if(!p) throw "error in constructor"; //генерирует исключение при
    //ошибке выделения памяти
    for(int i=0;i p[i] = 0; //заполнение вектора нулевыми элементами
    }
    void Vect::Print()
    {
    for(int i=0;i cout<
  • cout< }


    int main()
    {
    try
    {
    Vect a(3); //создаем вектор из 3 элементов
    a[0]=0;a[1]=1;a[2]=2;
    a.Print();
    Vect b(200); //создаем вектор из 200 элементов
    b[10] = 5; //ошибочная ситуация, т. к. объект не создан
    b.Print();
    }
    catch(char *msg)
    {
    cerr<<"Error:"< }
    return 0;
    }


    Исключения в деструкторах
    Если деструктор, вызванный во время раскрутки стека, попытается завершить свою работу при помощи исключения, то система вызовет функцию terminate(). На этапе отладки программы это допустимо, но в готовом продукте появление таких сообщений должно быть исключено.
    Следовательно, ни одно из исключений, которое могло бы появиться в процессе работы деструктора, не должно покинуть его пределы. Чтобы выполнить это требование:
    нельзя генерировать исключения в теле деструктора с помощью throw.
    если удаление объекта связано с вызовом других функций, относительно которых нет гарантий отсутствия генерации исключений, то рекомендуется объединить эти действия в некотором методе, например Destroy(), и вызывать данный метод с использованием блока try/catch.
    Т::Destroy()
    { // код, который может генерировать исключения
    }
    T::T()
    { try
    { Destroy(); }
    catch(…) { … }
    }

    1   ...   18   19   20   21   22   23   24   25   26


  • написать администратору сайта