When an object is thrown as exception then catch block should have its parameter declared by reference and not by value. In that way the same object will be assigned to reference variable.
#include <iostream> //main header
using namespace std;//for namespace
class MainFunda
{
public:
MainFunda(){ cout << "MainFunda()" << endl; }
A(const MainFunda& rhs)
{
cout << "MainFunda(copy constructor)"
<< endl;
}
~MainFunda()
{
cout << "~MainFunda()" << endl;
}
};
int main()
{
try
{
cout << "Starting try block" << endl;
throw MainFunda();
cout << "Ending try block" << endl;
}
catch (MainFunda& a)
{
cout << "Exception caught in catch(MainFunda&) : "
<< endl;
}
return 0;
}
The output:
Starting try block
MainFunda()
Exception caught in catch(MainFunda&) :
~MainFunda()
However, it is still possible to catch the exception by value, but there are 2 main problems in this approach
catch (MainFunda a) //catch by value
{
cout << "Exception caught in catch(MainFunda) : "
<< endl;
}
Copy Construction: First problem is that the constructor creates a new duplicate copy of thrown object. This parameter variable gets the copy and not original exception. The compiler invokes copy constructor to create this duplicate copy object
The compiler produces following output with such catch block:
Starting try block
MainFunda()
MainFunda(copy constructor)
Exception caught in catch(MainFunda) :
~MainFunda()
~MainFunda()
Object Slicing: Second, problem happens in case of inheritance. This is a scenario, when the argument is of type base class and exception is of type derived object. Here, compiler will slice the Derived class object. The exception object is initially of type Derived class but when it reaches inside the catch block it will become a Base object due to such slicing.
#include <iostream> //main header
using namespace std; //for namespace
class MFBase
{
public:
virtual void printtype()
{
cout << "Base Object" << endl;
}
};
class MFDerived : public MFBase
{
public:
virtual void printtype()
{
cout << "Derived Object" << endl;
}
};
int main()
{
try
{
cout << "Starting try block"
<< endl;
throw MFDerived();
cout << "Ending try block"
<< endl;
}
catch (MFBase b) //MFBase type, catch by value
{
cout << "Exception caught"
<< endl;
b.printtype();
}
return 0;
}
The output is as follows:
Starting try block
Exception caught
Base Object
The correct way to specify catch in this example is by reference:
catch (MFBase& b)//Base type parameter, catch by reference
{
cout << "Exception caught" << endl;
b.printtype();
}
The output will be as follows:
Starting try block
Exception caught
Derived Object
When multiple catch blocks match the type of exception thrown
In such case, the compiler will call the first catch block which matches the exception, and it ignores all the other catch blocks. The compiler will ignore the other catch blocks even if they are compatible. However, compiler shall generate warnings in such cases.
#include <iostream> //main header
using namespace std;//for namespace
class MFBase
{
public:
virtual void printtype()
{cout << "Base" << endl; }
};
class MFDerived : public MFBase
{
public:
virtual void printtype()
{cout << "Derived Object" << endl; }
};
int main()
{
try
{
cout << "Starting try block" << endl;
throw MFDerived();
cout << "Ending try block" << endl;
}
catch (MFBase& b)
{
cout << "Exception caught : MFBase&" << endl;
b.printtype();
}
catch (MFDerived& b)
{
cout << "Exception caught : MFDerived&" << endl;
b.printtype();
}
return 0;
}
The output is: