Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 213
Joald Avatar asked May 02 '18 11:05

Joald


2 Answers

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.

like image 136
Vittorio Romeo Avatar answered Sep 23 '22 13:09

Vittorio Romeo


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.

like image 24
Cory Kramer Avatar answered Sep 22 '22 13:09

Cory Kramer