C++ Exceptions and Inheritance from std::exception

2019-02-16 12:21发布

问题:

Given this sample code:

#include <iostream>
#include <stdexcept>

class my_exception_t : std::exception
{
public:
    explicit my_exception_t()
    { }

    virtual const char* what() const throw()
    { return "Hello, world!"; }
};

int main()
{
    try
        { throw my_exception_t(); }
    catch (const std::exception& error)
        { std::cerr << "Exception: " << error.what() << std::endl; }
    catch (...)
        { std::cerr << "Exception: unknown" << std::endl; }

    return 0;
}

I get the following output:

Exception: unknown

Yet simply making the inheritance of my_exception_t from std::exception public, I get the following output:

Exception: Hello, world!

Could someone please explain to me why the type of inheritance matters in this case? Bonus points for a reference in the standard.

回答1:

When you inherit privately, you cannot convert to or otherwise access that base class outside of the class. Since you asked for something from the standard:

§11.2/4:
A base class is said to be accessible if an invented public member of the base class is accessible. If a base class is accessible, one can implicitly convert a pointer to a derived class to a pointer to that base class (4.10, 4.11).

Simply put, to anything outside the class it's like you never inherited from std::exception, because it's private. Ergo, it will not be able to be caught in the std::exception& clause, since no conversion exists.



回答2:

Could someone please explain to me why the type of inheritance matters in this case? Bonus points for a reference in the standard.

The type of inheritance doesn't matter. It only matters that you have an accessible conversion available to one of the catch types. It just so happens that since it is not public inheritance there is no public accessible conversion.


Explanation:

You can see the same behavior here:

class B
{
};

class C1 : B
{
};

class C2 : public B
{
};

int main(int argc, char** argv)
{
    B& b1 = C1();//Compiling error due to conversion exists but is inaccessible
    B& b2 = C2();//OK
    return 0;
}

A thrown exception is only caught by a catch block if:

  1. The catch block has a matching type, or
  2. The catch block is for a type that has an accessible conversion
  3. The catch block is a catch(...)