Тип exception

Последнее обновление: 18.03.2023

Все исключения в языке C++ описываются типом exception, который определен в заголовочном файле <exception>. И при обработке исключений мы также можем использовать данный класс, интерфейс которого выглядит следующим образом

namespace std
{
	class exception
	{
	public:
		exception() noexcept;
		exception(const exception&) noexcept;
		exception& operator=(const exception&) noexcept;
		virtual ~exception(); // Destructor
		virtual const char* what() const noexcept; // возвращает сообщение об исключении
	};
}

Используем данный тип для обработки исключения:

#include <iostream>

double divide(int, int);

int main()
{
    int x {500};
    int y{};
    try
    {
        double z = divide(x, y);
        std::cout << z << std::endl;
    }
    catch (const std::exception& err)
    {
        std::cout << "Error!!!" << std::endl;
    }
    std::cout << "The End..." << std::endl;
}
 
double divide(int a, int b)
{
    if (!b)
        throw std::exception();
    return a / b;
}

Прежде всего, оператору throw передается объект типа std::exception

throw std::exception();

Если мы хотим отловить исключения типа exception, то нам надо в выражении catch определить переменную этого типа:

catch (const std::exception& err)

То есть здесь err представляет константную ссылку на объект exception. Если мы не собираемся использовать эту переменную в блоке catch, то можно указать просто тип исключения:

catch (std::exception)
{
	std::cout << "Error!!!" << std::endl;
}

С помощью функции what() можно получить сообщение об ошибке в виде строки в С-стиле. Однако непосредственно для типа std::exception он имеет мало смысла, поскольку просто выводит название класса. Но в производных классах он может использоваться для вывода сообщения об ошибке.

Создание производных классов

На основе класса std::exception мы можем создавать свои собственные типы исключений. Например:

#include <iostream>
 
class person_error: public std::exception
{
public:
    person_error(const std::string& message): message{message}
    {}
    const char* what() const noexcept override
    {
        return message.c_str();     // получаем из std::string строку const char*
    }
private:
    std::string message;    // сообщение об ошибке
};

class Person
{
public:
    Person(std::string name, unsigned age)
    {
        if(!age || age > 110)	// если age==0 или age > 110
            throw person_error("Invalid age");
        this->name = name;
        this->age = age;
    }
    void print() const
    {
        std::cout << "Name: " << name << "\tAge: " << age << std::endl;
    }
private:
    std::string name;
    unsigned age;
};
 
void testPerson(std::string name, unsigned age)
{
    try
    {
        Person person{name, age};   // создаем один объект Person
        person.print();
    }
    catch (const person_error& err) // обработка ошибок, сязанных с Person
    {
        std::cout << "Person error: " << err.what() << std::endl;
    }
    catch (const std::exception&)   // обработка остальных исключений
    {
        std::cout << "Something wrong"<< std::endl;
    }
}
int main()
{
    testPerson("Tom", 38);  // Name: Tom       Age: 38
    testPerson("Sam", 250);  // Person error: Invalid age
}

Здесь определен класс Person, который представляет пользователя. В конструктор класса передается имя и возраст. Однако передаваемое число может превышать разумный возраст или быть равно нулю. В этом случае мы генерируем исключение типа person_error:

Person(std::string name, unsigned age)
{
    if(!age || age > 110)	// если age==0 или age > 110
        throw person_error("Invalid age");

Класс person_error унаследован от std::exception, через конструктор получает сообщение об ошибке и хранит его в переменной message:

class person_error: public std::exception
{
public:
    person_error(const std::string& message): message{message}
    {}
    const char* what() const noexcept override
    {
        return message.c_str();     // получаем из std::string строку const char*
    }
private:
    std::string message;    // сообщение об ошибке
};

Для возвращения сообщения нам надо переопределить виртуальную функцию what(). Но проблема заключается в том, что функция возвращает строку const char*, но класс хранит сообщение в виде строки std::string. И чтобы получить из std::string значение const char*, у строки вызываем функцию c_str()

return message.c_str();     // получаем из std::string строку const char*

Для теста определена функция testPerson, в которой в блоке try создается объект Person. Конструкция try..catch использует два блока catch для обработки исключений. Первый блок обрабатывает исключения производного типа - класса person_error, а последний блок представляет базовый тип exceptionЖ

catch (const person_error& err) // обработка ошибок, сязанных с Person
{
    std::cout << "Person error: " << err.what() << std::endl;
}
catch (const std::exception&)   // обработка остальных исключений
{
    std::cout << "Something wrong"<< std::endl;
}

И в данном случае программа выдаст следующий результат:

Name: Tom       Age: 38
Person error: Invalid age
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850