Зачем бросать в производные классы уловы по базе?

Для приведенного ниже кода результатом является «EA Exception Finished», что означает, что, хотя мы бросили в производный класс, он пойман базовым классом. Это всегда? И если так, как я могу сделать уловки производного класса, таким образом появляется «EB Exception Finished»?

Также я не могу точно понять, что это значит throw EB() а также catch(EA&), И делает catch(EA&) означает, что блок catch получает ссылку для советника объект?

Извините за мое невежество. Если вы порекомендуете мне книгу или что-нибудь, чтобы сослаться на структуру исключений, это было бы очень полезно.

class EA {};
class EB: public EA {};

void F()
{
throw EB();  // throw at EB().
}

int main()
{
try
{
F();
}
catch(EA&) // caught here??
{
std::cout<<"EA Exception";
}
catch(EB&) // why not me? every time?
{
std::cout<<"EB Exception";
}

std::cout<<" Finished"<<std::endl;

return 0;
}

1

Решение

Причина:

Приведение к базовому типу

от производного класса к базе. и, следовательно, всегда застрять на первом улове.

1

Другие решения

Изменить порядок catch блоки для исправления такого поведения:

#include <iostream>

class EA {};
class EB: public EA {};

void F()
{
throw EB();  // throw at EB().
}

int main()
{
try
{
F();
}
catch(EB&) // why not me? every time?
{
std::cout<<"EB Exception";
}
catch(EA&) // caught here??
{
std::cout<<"EA Exception";
}

std::cout<<" Finished"<<std::endl;

return 0;
}

Компилятор даже предупреждает вас об этом:

main.cpp:21:3: warning: exception of type 'EB' will be caught
catch(EB&) // why not me? every time?
^~~~~
main.cpp:17:3: warning:    by earlier handler for 'EA'
catch(EA&) // caught here??
^~~~~
3

Как указано в стандарте в [Except.handle] (рабочий проект):

Обработчики для блока try пробуются в порядке появления. Это позволяет писать обработчики, которые никогда не могут быть выполнены, например, помещая обработчик для производного класса после обработчика для соответствующего базового класса.

Это именно то, что вы сделали. Действительно интересно.
Инвертируйте обработчики, чтобы решить проблему.

2

Потому что блоки catch проверяют в том порядке, в котором вы их объявляете.

ты первый поймал EA&,
EB получен из EA, так что это допустимый улов, а второй улов игнорируется.

Сначала вы хотите получить наиболее «специализированную» функцию исключения. Так что если вы переключаете блоки захвата, он должен работать по-другому.

1

Заявки на вылов проверяются по порядку. EA& совпадает, поэтому он используется. EB& никогда не может быть сопоставлен Вы должны поставить более конкретный улов в первую очередь.

  catch(EB&) // Will catch
{
std::cout<<"EB Exception";
}
catch(EA&) // and this would catch EA objects that aren't EB.
{
std::cout<<"EA Exception";
}
1