In a hierarchy of exception classes, What is the correct ordering of catch statements so as to allow exceptions of more than one class from the hierarchy of exception classe
Most derived first. Handlers are matched in the order they appear, so you want the most specific ones first.
My answer is according to linux compiler and hopefully it should be true for all. The order of the catch depends on 2 factors:
(1) First come first choice; If base class appears before derived then it will be given choice. Some compilers warns about that, some don't;
(2) Type of inheritance; Either public or non-public (private/protected)
struct B {};
struct D : B {};
struct DD : D {};
int main()
{
for(int i = 0; i < 3; i++)
{
try
{
switch(i)
{
case 0: throw new B;
case 1: throw new D;
case 2: throw new DD;
}
}
catch(B *o) { cout<<"B* caught\n"; }
catch(D *o) { cout<<"D* caught\n"; }
catch(DD *o) { cout<<"DD* caught\n"; }
}
}
(1) In above code, it always catches B. if you change the order with catching DD, D, B then it will be as per your expectations where Derived classes will be given preference.
(2) Now replace 'struct' with 'class' or change inheritance to private/protected; In above code irrespective of order, the catches will match the type of throw. It will be such strict that even if you remove any of the catch of Derived class, it won't be caught by Base class.
The correct ordering should be the most derived first. The handlers must be in the order from most derived to the Base class.
Here's an code example:
#include <iostream>
using namespace std;
class MyException
{
public:
MyException(int value):mValue(value)
{
}
int mValue;
};
class MyDerivedException: public MyException
{
public:
MyDerivedException(int value, int anotherValue):MyException(value),mAnotherValue(anotherValue)
{
}
int mValue;
int mAnotherValue;
};
void doSomething()
{
//Lot of Interesting stuff
//Exception condition
throw MyDerivedException(10,20);
}
int main()
{
try
{
doSomething();
}
catch(MyDerivedException &exception)
{
cout<<"\nCaught Derived Class Exception\n";
}
catch(MyException &exception)
{
cout<<"\nCaught Base Class Exception\n";
}
return 0;
}
In the above example the handlers are ordered as Derived class(MyDerivedException) and then the Base class(MyException). If the order of these handlers is reversed then the Base class handler will catch all the exceptions thrown(even if they are of the Derived class). This is because one can always assign a Derived class object/pointer to object/pointer of a Base class without any typecasting or explicit handling.
Hth.