Исключения в C ++ и наследование от std :: exception - PullRequest
12 голосов
/ 03 апреля 2010

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

#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!

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

Ответы [ 2 ]

21 голосов
/ 03 апреля 2010

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

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

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

10 голосов
/ 03 апреля 2010

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

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


Пояснение:

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

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

Брошенное исключение перехватывается блоком перехвата, только если:

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