Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++: Throwing a derived class by reference does not work when catching base class

I want to throw my own exceptions with the base class Exception. There is a virtual method print which will be overwritten by the subclasses. I only catch the type Exception& and use print to get the specific error. The problem is that once I throw a reference of a subclass it is trated as if it were the base class.

Here is an example:

#include <iostream>
using namespace std;

class Exception
{
    public:
        virtual void print()
        {
            cout << "Exception" << endl;
        }
};

class IllegalArgumentException : public Exception
{
    public:
        virtual void print()
        {
            cout << "IllegalArgumentException" << endl;
        }
};

int main(int argc, char **argv)
{
    try
    {
        IllegalArgumentException i;
        Exception& ref = i;

        cout << "ref.print: ";
        ref.print();

        throw ref;
    }
    catch(Exception& e)
    {
        cout << "catched: ";
        e.print();
    }
}

The output of this example is:

ref.print: IllegalArgumentException
catched: Exception

Using a reference should result in the print method from the derived class being used. Inside the try block the reference does use it. Why doesn't the catched Exception& act like an IllegalArgumentException and how can I get that behavior?

The following code seems to do what it is supposed to:

try
{
    IllegalArgumentException i;
    Exception* pointer = &i;

    throw pointer;
}
catch(Exception* e)
{
    cout << "pointer catched: ";
    e->print();
}

but doesn't the pointer become possibly invalid outside the scope of the try block? It would then be risky to do this and if I allocate memory on the heap to get around that problem I have the responsibility for the deletion inside the catch block which isn't pretty either. So how would you solve the problem?

like image 406
user1286875 Avatar asked Mar 22 '12 20:03

user1286875


People also ask

Will a catch statement catch a derived exception if it is looking for the base class?

Catching base and derived classes exceptions in C++To catch an exception for both base and derive class then we need to put catch block of derived class before the base class. Otherwise, the catch block of derived class will never be reached.

Can be inherited by a derived class from a base class?

The derived class inherits all members and member functions of a base class. The derived class can have more functionality with respect to the Base class and can easily access the Base class. A Derived class is also called a child class or subclass.

Can a base class pointer contain reference of its derived class?

// As base-class pointer cannot access the derived class variable.

What is the connection between the base class and the derived class?

The class whose members are inherited is called the base class, and the class that inherits those members is called the derived class. A derived class can have only one direct base class. However, inheritance is transitive.


1 Answers

throw implicitly copies, and consequently slices. Quoting C++11, §15.1/3:

A throw-expression initializes a temporary object, called the exception object, the type of which is determined by removing any top-level cv-qualifiers from the static type of the operand of throw and adjusting the type from “array of T” or “function returning T” to “pointer to T” or “pointer to function returning T”, respectively. The temporary is an lvalue and is used to initialize the variable named in the matching handler. If the type of the exception object would be an incomplete type or a pointer to an incomplete type other than (possibly cv-qualified) void the program is ill-formed. Except for these restrictions and the restrictions on type matching mentioned in 15.3, the operand of throw is treated exactly as a function argument in a call or the operand of a return statement.

I've seen a handful of codebases that work around this by throwing pointers to exceptions rather than objects directly, but personally I'd just reconsider your "need" to do this in the first place.

like image 180
ildjarn Avatar answered Sep 22 '22 12:09

ildjarn