Why throw at derived class catches by base?
Asked Answered
G

5

1

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;
}
Giltzow answered 16/9, 2016 at 9:25 Comment(1)
An exception is always caught by the first catch block that can catch it, so your order is wrong.Keefer
M
1

Reason:

Upcasting

of derived class to base. and hence always getting stuck on the first catch.

Montmartre answered 19/9, 2016 at 6:11 Comment(0)
W
3

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??
   ^~~~~
Weirdo answered 16/9, 2016 at 9:29 Comment(2)
Thanks a lot! What does it mean by throw EB() in this context? What compiler do you use?Giltzow
@DongkyuChoi I used GCC at coliruBurgrave
C
2

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.

Cairn answered 16/9, 2016 at 18:9 Comment(0)
B
1

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.

Bodkin answered 16/9, 2016 at 9:28 Comment(2)
Thanks a lot! So throw to derived class can be also caught by base class, but it is not desirable because it cannot be a specialized treatment?Giltzow
It can be done if you change the order of the "catch" block. Also as mentioned in another answer. You should get warnings in those cases.Bodkin
E
1

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";
  }
Evaporimeter answered 16/9, 2016 at 9:29 Comment(2)
Thanks a lot! Then EB catches first and then EA also catch consequently?Giltzow
No. Only the first matching catch block is executed. it's quite common to have a catch block for a specific exception, for const std::exception&, and for .... Each printing successively less detailed information.Evaporimeter
M
1

Reason:

Upcasting

of derived class to base. and hence always getting stuck on the first catch.

Montmartre answered 19/9, 2016 at 6:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.