I just came up with a problem when I learned about using Exceptions. The code is as follows.
// exception constructor
#include <iostream> // std::cout
#include <exception> // std::exception
#include <cxxabi.h>
#define PRINT_TYPENAME(f) std::cout << abi::__cxa_demangle(typeid(f).name(), 0, 0, &status) << std::endl;
struct ooops : std::exception
{
const char *what() const noexcept { return "Ooops!\n"; }
};
int main()
{
ooops e;
std::exception *p = &e;
// demangle the typeid
char *realname;
int status;
PRINT_TYPENAME(p);
PRINT_TYPENAME(*p);
try
{
throw e; // throwing copy-constructs: ooops(e)
}
catch (std::exception &ex)
{
std::cout << ex.what();
}
try
{
throw *p; // throwing copy-constructs: std::exception(*p)
}
catch (std::exception &ex)
{
std::cout << ex.what();
}
return 0;
}
The output is:
std::exception*
ooops
Ooops!
std::exception
It seems that *p has the type of the derived class. However, when std::exception &ex=*p, the type_id.name() of ex becomes the base class rather than the derived class.
Since *p and ex have the same type. I feel confused about why the type of ex differs between the two try-catch sentences.
Can someone tell me the reason? Thanks for the help.
When an exception is thrown, the exception object is copy-initialized from your throw expression. I.e., rather than std::exception &ex = *p;, it's more like you did std::exception temp = *p; and then std::exception& ex = temp;.
This results in object slicing, where the derived part of your class is "sliced off". This is why inside your catch handler, the dynamic type of ex is std::exception instead of oops.
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