try
{
throw Derived();
}
catch (Base&)
{
std::cout << "subtyping\n";
}
try
{
throw "lol";
}
catch (std::string)
{
std::cout << "coercion\n";
}
Выход:
subtyping
terminate called after throwing an instance of 'char const*'
Почему обработка исключений хорошо работает с подтипами, а не с принуждением?
Поймать сгенерированные исключения весьма отличается от передачи аргументов в функции.
Есть сходства, но есть и тонкие различия.
3 основных отличия:
catch
пункты рассматриваются в порядке их объявления (не подходят)const void*
ловит любой указатель)Любой другой вид конверсии не допускается (например, int
в double
или неявный const char*
в string
— твой пример).
По поводу вашего вопроса в комментарии
Предположим, существует иерархия:
class Base {};
class Derived: public Base {};
class Base2 {};
class Leaf: public Derived, public Base2 {};
Теперь в зависимости от порядка catch
пункты, соответствующий блок будет выполнен.
try {
cout << "Trying ..." << endl;
throw Leaf();
} catch (Base& b) {
cout << "In Base&";
} catch (Base2& m) {
cout << "In Base2&"; //unreachable due to Base&
} catch (Derived& d) {
cout << "In Derived&"; // unreachable due to Base& and Base2&
}
Если вы переключаетесь Base
а также Base2
поймать порядок вы заметите другое поведение.
Если Leaf
унаследовано в частном порядке от Base2
, затем catch Base2&
будет недоступен вне зависимости от того, где находится (при условии, что мы бросаем Leaf
)
Вообще все просто: порядок имеет значение.
Пункт 15.3 / 3 Стандарта C ++ 11 определяет точные условия для соответствия обработчика определенному объекту исключения, и они не позволяют пользовательские преобразования:
Обработчик соответствует объекту исключения типа
E
если— Обработчик типа
cv T
или жеcv T&
а такжеE
а такжеT
одного типа (игнорируя верхний уровеньcv
-qualifiers),
или же— обработчик типа
cv T
или жеcv T&
а такжеT
является однозначным публичным базовым классомE
, или же— обработчик типа
cv1 T* cv2
а такжеE
тип указателя, который может быть преобразован в тип
обработчик одним или обоими
стандартное преобразование указателя (4.10), не включающее преобразование указателей в приватные или защищенные
или неоднозначные классыпреобразование квалификации
— обработчик является указателем или указателем на тип элемента и
[…]E
являетсяstd::nullptr_t
,