What is the type of the exception object in the following thrown:
Question1> range_error r("error"); throw r;
Answer1> an object of range_error
Question2> exception *p = &r; throw *p;
Answer2> a sliced object of exception
Question3> exception *p = &r; throw p;
Answer3> a pointer pointing to range_error is thrown. The capture-handling can access the range_error member functions through dynamic binding.
Do I get these question right?
// Updated and Compiled and Run on VS2010
#include <iostream>
using namespace std;
class ExClassA
{
public:
virtual void PrintMe() const
{
cout << "ExClassA" << endl;
}
};
class ExClassB : public ExClassA
{
public:
virtual void PrintMe() const
{
cout << "ExClassB" << endl;
}
};
int main(int argc, char* argv[])
{
ExClassB exClassB;
ExClassA *p = &exClassB;
try
{
throw *p;
}
catch (const ExClassA& e)
{
e.PrintMe();
}
try
{
throw p;
}
catch (const ExClassA* e)
{
e->PrintMe();
}
}
The first try-catch of above program prints "ExClassA"
The second try-catch of above program prints "ExClassB"
Dereferencing is used to access or manipulate data contained in memory location pointed to by a pointer. *(asterisk) is used with pointer variable when dereferencing the pointer variable, it refers to variable being pointed, so this is called dereferencing of pointers.
Dereferencing a pointer means getting the value that is stored in the memory location pointed by the pointer. The operator * is used to do this, and is called the dereferencing operator.
In computer programming, a dereference operator, also known as an indirection operator, operates on a pointer variable. It returns the location value, or l-value in memory pointed to by the variable's value. In the C programming language, the deference operator is denoted with an asterisk (*).
Dereferencing is getting at the pointed value. Pointer variables are useful for walking the contents of a linked list data structure, using a dynamic jump table to subroutines, and passing arguments by address (so only an address is passed) rather than by value (where the entire data structure is copied).
Throwing an object always results in the thrown object being a copy of the object you threw, based on the static type of that object. Thus your first two answers are correct.
The third one is a little more complicated. If you catch(range_error*)
you won't catch the exception because the types don't match. If you catch(exception*)
you won't be able to access members of range_error
in the caught pointer; you can dynamic_cast
that pointer back to a range_error pointer though.
I think you are right in all three. The type of the thrown object (IIRC) is the static type of the object being thrown. I would have to dig into the standard for a while to find the exact quotes, but a simple example seems to confirm this:
struct base {};
struct derived : base {};
void t() {
derived d;
base * b = &d;
throw *b;
}
int main() {
try {
t();
} catch ( derived const & ) {
std::cout << "derived" << std::endl;
} catch ( base const & ) {
std::cout << "base" << std::endl;
}
}
If the dynamic type of the object being thrown was used, then *b
would have type derived
and the first catch
would succeed, but empirically the second catch
is executed (g++).
In the last case, the object thrown is a pointer to exception
that refers to a range_error
object. The slight difference is again what can be caught, the compiler will not catch in a catch (range_error*)
block. The answer is correct, but I would have specified the type of the pointer, as much as the type of the pointee. (The type of the pointer is somehow implicit in the answer)
All three answers are correct. Just note that you'll have to catch a pointer type in the third case.
The usual way to throw an exception is:
throw range_error("error");
At the throw site, you normally know the exact type of exception you want to throw. About the only exception I can think of is when the exception was passed in as an argument, e.g.:
void f( std::exception const& whatToDoInCaseOfError )
{
// ...
throw whatToDoInCaseOfError; // slices
}
It's not a frequence case, but if you want to support it, you'll need a
separate exception hierarchy of your own, with a virtual raise
function:
class MyExceptions
{
public:
virtual ~MyExceptions() {}
virtual void raise() const = 0;
};
template<typename ExceptionType>
class ConcreteException : public ExceptionType, public MyExceptions
{
public:
virtual void raise() const
{
throw *this;
}
};
The client code then wraps the exception he wants to be thrown in a
ConcreteException
, and you call the raise
function on it, rather
than invoke throw
directly.
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