Joald
Joald

Reputation: 1134

Can't catch class derived from std::exception by reference to std::exception

I created a custom exception class that derives from std::exception.

#include <iostream>

class Exception : std::exception {
public:
    const char* what() const noexcept override {
        return "test";
    }
};

int main() {
    try {
        throw Exception();
    } catch (std::exception& e) {
        std::cout << e.what() << std::endl;
    }
}   

This program, when compiled by g++ -stdc++=17 on Ubuntu, causes the exception to not get caught by the catch block, even though catching by reference is supposed to catch derived exceptions too. It calls std::terminate, even though it happens in a try block that catches its base class by reference. Same thing happens if Exception inherits from std::runtime_error and passes "test" to the std::runtime_error constructor in its own constructor. Normally the solution would be to only catch using Exception, but in my original code I need to catch different types of exceptions, all of which inherit from std::exception. Why does this happen? Does catching by reference to base not work? How can I catch all exceptions deriving from std::exception using one catch block?

Upvotes: 8

Views: 2136

Answers (2)

Vittorio Romeo
Vittorio Romeo

Reputation: 93264

When you inherit from a base class during the definition of a class, the default access modifier for the inheritance is private. This means that the two following definitions are equivalent:

class derived : base { /* ... */ };
class derived : private base { /* ... */ };

The language doesn't allow1 you to refer to a derived class from a private base2. As an example, the following code does not compile:

int main()
{
    derived d;
    base& b = d; // <== compilation error
}
error: 'base' is an inaccessible base of 'derived'
     base& b = d;
               ^

live example on wandbox.org


This is the reason why your catch block cannot handle Exception. Change your inheritance to public...

class Exception : public std::exception

...and your original code will work.

live example on wandbox.org


1 See [dcl.init.ref] and [conv.ptr].

2 Unless you're in the scope of derived itself. See this live example on wandbox.org.

Upvotes: 10

Cory Kramer
Cory Kramer

Reputation: 117856

You need to publicly derive from std::exception

class Exception : public std::exception

Then your output is

test

For more details about this topic, please reference Difference between private, public, and protected inheritance.

Upvotes: 4

Related Questions