For the code below, result is "EA Exception Finished", which means although we threw at derived class it caught by base class. Is it always? And if so, how can I make the derived class catches, thus "EB Exception Finished" appears?
Also I can't exactly get what does it mean by throw EB()
and catch(EA&)
. And does catch(EA&)
means the catch block gets a reference for EA object?
Sorry for my ignorance. If you recommend me a book or something to refer about exception structure, that'd be great help.
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;
}
Reason:
Upcasting
of derived class to base. and hence always getting stuck on the first catch.
Change the order of the catch
blocks to fix that behavior:
#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;
}
The compiler even warns you about this:
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??
^~~~~
As mentioned by the standard in [except.handle] (working draft):
The handlers for a try block are tried in order of appearance. That makes it possible to write handlers that can never be executed, for example by placing a handler for a derived class after a handler for a corresponding base class.
That's exactly what you did. Interesting indeed.
Invert the handlers to solve the issue.
Because the catch blocks check in the order you declare them.
you first catch by EA&
.
EB is derived from EA, so this is a valid catch and the second catch gets ignored.
You want to have the most "specialized" exception-catch first. So if you switch the catch blocks it should work the other way.
catch statements are inspected in order. EA&
matches, so it is used. EB&
can never be matched. You need to put the more specific catch first.
catch(EB&) // Will catch
{
std::cout<<"EB Exception";
}
catch(EA&) // and this would catch EA objects that aren't EB.
{
std::cout<<"EA Exception";
}
来源:https://stackoverflow.com/questions/39527963/why-throw-at-derived-class-catches-by-base