Преобразования типов и исключения (проверь себя)

Главная Форумы Программирование Программирование на С++ Преобразования типов и исключения (проверь себя)

В этой теме 0 ответов, 1 участник, последнее обновление  Васильев Владимир Сергеевич 1 год назад.

  • Автор
    Сообщения
  • #3117

    Знаете ли вы, какие преобразования типов возможны в момент перехвата исключения?

    В приведенном ниже фрагменте кода функция throw_catch принимает в качестве шаблона два типа данных (throw_type и catch_type), вырабатывает исключение типа throw_type, при этом блок try имеет два обработчика. Первый обработчик имеет тип catch_type, а второй throw_type (он будет однозначно вызван, если до него дойдет управление). При этом, т.к. обработчики исключений перебираются последовательно и сработает лишь один из них, то мы узнаем допускает С++ преобразование типа throw_type в тип catch_type при обработке исключений или нет.

    #include <iostream>
    #include <string>
    #include <typeinfo>
    
    class A
    {
    };
    
    class B
    {
    public:
    
        B()
        {
        }
    
        B(A const&)
        {
        }
    
        operator A()
        {
            return A();
        }
    };
    
    template <class throw_type, class catch_type>
    void throw_catch(throw_type trw = throw_type())
    {
        try
        {
            throw trw;
        }
        catch(catch_type)
        {
            std::cout << typeid(catch_type).name() << std::endl;
        }
        catch(throw_type)
        {
            std::cout << typeid(throw_type).name() << std::endl;
        }
    }
    
    int main()
    {
        throw_catch <char*, void*> ();
        throw_catch <void*, char*> ();
    
        throw_catch <char*, void const*> ();
        throw_catch <char const*, void*> ();
    
        throw_catch <char*, void volatile*> ();
        throw_catch <char volatile*, void*> ();
    
        throw_catch <char, int> ();
        throw_catch <int, char> ();
    
        throw_catch <A, B> ();
        throw_catch <B, A> ();
    
        throw_catch <char const*, std::string> ("Hello");
    
        return 0;
    }

    Каждый обработчик исключения в нашем примере выводит на экран имя типа, к которому было приведено исключение. Таким образом, при вызове:
    throw_catch <char*, void*> ();
    будет напечатано void* если преобразование char* в void* допустимо, а в противном случае – char*.

    Для вывода имени типа тут использовался модуль typeinfo, однако typeid(Type).name() может выводить не все имя, а некоторое сокращение (в зависимости от компилятора результат может меняться).

    Что мы увидим на экране в результате работы приведенной программы (вопрос не о псевдонимах типов typeinfo, а о допустимых преобразованиях при обработке исключений)?

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

    void *
    void *
    void const *
    char const *
    void volatile *
    char volatile *
    char
    int
    class A
    class B
    char const *

    Обратите внимание, что тип B может быть приведен к типу А, при этом выполнится срезка (чтобы избежать ее нужно использовать указатели или ссылки). Тип A не может быть приведен к типу B, т.к. базовый класс не может приводиться к дочернему. Тип char const * не будет приведен к типу string, хотя у последнего есть соответствующий конструктор.

Для ответа в этой теме необходимо авторизоваться.