In this C++ tutorial, in the section titled "Standard exceptions", there is this example code which uses a class derived from the standard exception class in the STL:
// standard exceptions
#include <iostream>
#include <exception>
using namespace std;
class myexception: public exception
{
virtual const char* what() const throw()
{
return "My exception happened";
}
} myex; //Declares an instance of myexception outside of the main function
int main () {
try
{
throw myex;
}
catch (exception& e) //My question is regarding this line of code
{
cout << e.what() << endl;
}
return 0;
}
That code prints out My exception happened
. However, if I remove the ampersand, it prints out std::exception
, which is what happens when you call what()
with the standard exception class, not the derived class.
The website gives this explanation:
We have placed a handler that catches exception objects by reference (notice the ampersand & after the type), therefore this catches also classes derived from exception, like our myex object of class myexception.
Is throwing myex
kind of like "calling a the catch
function, and passing myex
as a parameter"? Because it that case, I would imagine that it doesn't matter whether you throw the exception by value or by reference (that's what the ampersand does right?), because you are still throwing a myexception
rather than an exception
. And due to dynamic binding and polymorphism or something like that, e.what()
should still print out My exception happened
rather than std::exception
.
This is happening due to object slicing.
If you assign an object of a derived class to an instance of a base class (as in the case of using a copy c'tor when passing by value) all the information of the derived class will be lost (sliced).
For example,
class Base {
int baseInfo;
};
class Derived : public Base
{
int someInfo;
};
Then if you were to write this:
Derived myDerivedInstance;
Base baseInstance = myDerivedInstance;
Then the "someInfo" in myDerivedInstance
is sliced away in baseInstance
.
You can kind of think of it like that, but (like a function call), the exception is passed by value to the catch
handler. Since it's passed by value, it's copied to a std::exception
local to the catch
handler. It does that with std::exception
s copy constructor, in which case the copy no longer has any private data held by a myexception
, nor the derived functions. Functions do the exact same thing. This is called "object slicing", and is why you never store virtual base types by value, only by pointer or reference. You'd see the same behavior with a std::vector<std::exception>
. Contained elements would lose all derived data.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With