Почему это работает?C++ исключение наследования неоднозначность
#include <exception>
#include <iostream>
#include <stdexcept>
#include <boost/exception/all.hpp>
struct foo_error : virtual boost::exception, public std::runtime_error
{
explicit foo_error(const char* what)
: std::runtime_error(what)
{ }
explicit foo_error(const std::string& what)
: std::runtime_error(what)
{ }
};
struct bar_error : virtual boost::exception, public std::runtime_error
{
explicit bar_error(const char* what)
: std::runtime_error(what)
{ }
explicit bar_error(const std::string& what)
: std::runtime_error(what)
{ }
};
struct abc_error : virtual foo_error, virtual bar_error
{
explicit abc_error(const char* what)
: foo_error(what), bar_error(what)
{ }
explicit abc_error(const std::string& what)
: foo_error(what), bar_error(what)
{ }
};
static void abc()
{
throw abc_error("abc error");
}
int main()
{
try
{
abc();
}
catch (const std::exception& e)
{
std::cerr << e.what();
}
}
Я думал, что это не должно составить из-за неоднозначного перехода от abc_error
к std::exception
. Что мне не хватает? Я придумал диаграмму наследования, и я не могу понять, почему этот код работает (стрелки обозначают виртуальное наследование, а строки обозначают не виртуальное наследование).
std::exception std::exception
+ +
| |
| |
+ +
std::runtime_error std::runtime_error
+ +
| |
| +-->boost::exception<-+ |
+ | | +
foo_error+<-----+ +--->+bar_error
| |
| |
| |
+abc_error+
Похоже abc_error
включает в себя два экземпляра std::exception
так catch
(или мне так казалось), не должен быть в состоянии бросить abc_error
в std::exception
. Или это должно быть?
UPDATE
Я не могу ответить на мои собственные вопросы на данный момент, поэтому я буду продолжать здесь. Я сузил проблему до:
struct NonVirtualBaseBase { };
struct NonVirtualBase : NonVirtualBaseBase { };
struct VirtualBase { };
struct A : virtual VirtualBase, NonVirtualBase { };
struct B : virtual VirtualBase, NonVirtualBase { };
struct C : A, B { };
int main()
{
try
{
throw C();
}
catch (const VirtualBase& e)
{
return 1;
}
return 0;
}
Образец выше работает должным образом и является прекрасным фрагментом кода. Он сработает, если я заменил catch (const VirtualBase& e)
на catch (const NonVirtualBase& e)
, который, по моему мнению, является нормальным и имеет смысл. Но он также работает, если я заменю ту же строку catch (const NonVirtualBaseBase& e)
, которая мне кажется странной и неправильной. Ошибка компилятора?
+1 для хорошо отформатированного кода, хороший вопрос с объяснением и классный ASCII art :) –
Какой компилятор это? – Agentlien
@Agentlien Это Microsoft (R) C/C++ Оптимизация компилятора Версия 16.00.30319.01 для x64 –