Исключения и наследование С++ из std:: exception

Учитывая этот пример кода:

#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;
}

Я получаю следующий вывод:

Exception: unknown

Но просто делая наследование my_exception_t из std::exception public, я получаю следующий вывод:

Exception: Hello, world!

Не мог бы кто-нибудь объяснить мне, почему в этом случае имеет значение тип наследования? Бонусные баллы для справки в стандарте.

Ответ 1

Когда вы наследуете конфиденциально, вы не можете конвертировать или иным образом обращаться к этому базовому классу за пределами класса. Поскольку вы просили что-то из стандарта:

§11.2/4:
Говорят, что базовый класс доступен, если доступный публичный член базового класса доступен. Если базовый класс доступен, можно неявно преобразовать указатель на производный класс в указатель на этот базовый класс (4.10, 4.11).

Проще говоря, для чего-либо вне класса это похоже на то, что вы никогда не унаследовали от std::exception, потому что он закрыт. Ergo, он не сможет попасть в предложение std::exception&, поскольку никакого преобразования не существует.

Ответ 2

Может кто-нибудь, пожалуйста, объясните мне, почему тип наследования имеет значение в Это дело? Бонусные баллы за ссылка в стандарте.

Тип наследования не имеет значения. Важно только то, что у вас есть доступное преобразование, доступное для одного из типов catch. Так получилось, что, поскольку это не общедоступное наследование, нет общедоступного преобразования.


Объяснение:

Здесь вы можете увидеть такое же поведение:

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;
}

Исключенное исключение попадает только в блокирующий блок, если:

  • Блок catch имеет соответствующий тип или
  • Блок catch предназначен для типа доступного преобразования
  • Блок catch - это catch (...)