|
||||
|
Section 17:
|
[17.16] How do I throw polymorphically?
Sometimes people write code like:
class MyExceptionBase { };
class MyExceptionDerived : public MyExceptionBase { };
void f(MyExceptionBase& e)
{
// ...
throw e;
}
void g()
{
MyExceptionDerived e;
try {
f(e);
}
catch (MyExceptionDerived& e) {
...code to handle MyExceptionDerived...
}
catch (...) {
...code to handle other exceptions...
}
}
If you try this, you might be surprised at run-time when your catch
(...) clause is entered, and not your catch (MyExceptionDerived&)
clause. This happens because you didn't throw polymorphically. In function
f(), the statement throw e; throws an object with the same
type as the static type of the expression e. In other words,
it throws an instance of MyExceptionBase. The throw statement
behaves as-if the thrown object is copied, as opposed to
making a "virtual copy".
Fortunately it's relatively easy to correct:
class MyExceptionBase {
public:
virtual void raise();
};
void MyExceptionBase::raise()
{ throw *this; }
class MyExceptionDerived : public MyExceptionBase {
public:
virtual void raise();
};
void MyExceptionDerived::raise()
{ throw *this; }
void f(MyExceptionBase& e)
{
// ...
e.raise();
}
void g()
{
MyExceptionDerived e;
try {
f(e);
}
catch (MyExceptionDerived& e) {
...code to handle MyExceptionDerived...
}
catch (...) {
...code to handle other exceptions...
}
}
Note that the throw statement has been moved into a virtual function.
The statement e.raise() will exhibit polymorphic behavior, since
raise() is declared virtual and e was passed by
reference. As before, the thrown object will be of the static type of
the argument in the throw statement, but within
MyExceptionDerived::raise(), that static type is
MyExceptionDerived, not MyExceptionBase.
|
|||