我应该从std::exception继承吗? 我见过至少一个可靠的源(C++类I)建议C++中的应用程序特定异常类应该继承 STD::异常< /代码>。我不清楚这种方法的好处

我应该从std::exception继承吗? 我见过至少一个可靠的源(C++类I)建议C++中的应用程序特定异常类应该继承 STD::异常< /代码>。我不清楚这种方法的好处,c++,exception,exception-handling,C++,Exception,Exception Handling,在C#中,从ApplicationException继承的原因很清楚:您可以获得一些有用的方法、属性和构造函数,只需添加或重写所需的内容。使用std::exception时,您似乎只能得到一个要重写的what()方法,您也可以自己创建它 那么,使用std::exception作为特定于应用程序的异常类的基类有什么好处(如果有的话)?有什么好的理由不从std::exception继承吗?您可能希望从std::exception继承的原因是,它允许您抛出根据该类捕获的异常,即: class myEx

在C#中,从
ApplicationException
继承的原因很清楚:您可以获得一些有用的方法、属性和构造函数,只需添加或重写所需的内容。使用
std::exception
时,您似乎只能得到一个要重写的
what()
方法,您也可以自己创建它


那么,使用
std::exception
作为特定于应用程序的异常类的基类有什么好处(如果有的话)?有什么好的理由不从
std::exception
继承吗?

您可能希望从
std::exception
继承的原因是,它允许您抛出根据该类捕获的异常,即:

class myException : public std::exception { ... };
try {
    ...
    throw myException();
}
catch (std::exception &theException) {
    ...
}


你是否应该继承它取决于你自己。标准
std::exception
及其标准后代提出了一种可能的异常层次结构(分为
logic\u error
subhierarchy和
runtime\u error
subhierarchy)和一种可能的异常对象接口。如果你喜欢,就用它。如果出于某种原因您需要一些不同的东西,请定义您自己的异常框架。

主要的好处是,使用类的代码不必知道您抛出的内容的确切类型,而只需捕获
std::exception



编辑:正如Martin和其他人所指出的,您实际上想要从
标题中声明的
std::exception
的子类之一派生。

如果所有可能的异常都来自
std::exception
,那么您的catch块可以简单地
捕获(std::exception&e)
,并确保捕获所有内容


捕获异常后,可以使用
what
方法获取更多信息。C++不支持鸭子类型,所以另一个类有<代码>什么< /Cult>方法需要不同的捕获和不同的代码来使用它。

< P>继承从<代码> STD::异常< /代码>是异常的“标准”基类,所以对于团队中的其他人来说是自然的,例如要预料到这一点并捕获base
std::exception


如果您想方便起见,可以从提供
std::string
构造函数的
std::runtime\u error
继承。

由于该语言已经抛出std::exception,因此您无论如何都需要捕获它以提供适当的错误报告。您也可以对自己的所有意外异常使用相同的捕获。而且,几乎任何抛出异常的库都会从std::exception派生它们

换句话说,它不是

catch (...) {cout << "Unknown exception"; }

捕获(…){cout继承有一个问题,您应该了解对象切片。当您编写
throw e;
时,throw表达式初始化一个临时对象,称为异常对象,其类型是通过从
throw
的操作数的静态类型中删除任何顶级cv限定符来确定的这不是你所期望的。你能找到的问题的例子


这不是反对继承的论点,它只是“必须知道”的信息。

您应该继承自。它提供了更多的功能和易于理解的方式来携带额外的数据……当然,如果您不使用,请忽略此建议。

std::exception的问题在于没有构造函数(在标准兼容版本中)接受消息的


因此,我更喜欢从
std::runtime\u error
派生。这是从
std::exception
派生的,但是它的构造函数允许您将C字符串或
std::String
传递给构造函数,当
what()
被调用。

我曾经参与清理一个大型代码库,以前的作者在这里抛出int、HRESULTS、std::string、char*、random类……到处都是不同的东西;只要说出一个类型,它可能被抛出到某个地方。而且根本没有公共基类。相信我,一旦我们到达poi,事情就变得更加整洁了nt所有抛出的类型都有一个共同的基础,我们可以捕捉到并且知道什么都不会过去。所以请帮你自己(以及那些将来必须维护你的代码的人)一个忙,从一开始就这样做。

是的,你应该从
std::exception
派生


其他人回答说,
std::exception
存在无法向其传递文本消息的问题,但是在抛出时尝试格式化用户消息通常不是一个好主意。相反,使用exception对象将所有相关信息传输到catch站点,然后该站点可以格式化用户友好的消息sage.

是否从任何标准异常类型派生是第一个问题。这样做可以为所有标准库异常和您自己的异常启用单个异常处理程序,但也会鼓励此类捕获所有异常处理程序。问题是,只应捕获知道如何处理的异常。在main()中例如,如果在退出之前将what()字符串作为最后手段记录下来,那么捕获所有std::异常可能是一件好事

一旦您决定是否从标准异常类型派生,那么问题是应该以哪种类型为基础。如果您的应用程序不需要i18n,您可能会认为在调用站点格式化消息与在调用站点保存信息和生成消息一样好。问题是可能不需要消息。最好使用惰性消息生成方案--
catch (const std::exception &e) { cout << "unexpected exception " << e.what();}
Library API: Exception caught in function 'api_function'
Backtrace:
~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed
~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"
try
{
  // something that may throw
}
catch( const MyException & ex )
{
  // do something specialized with the
  // additional info inside MyException
}
catch( const std::exception & ex )
{
  std::cerr << ex.what() << std::endl;
}
catch( ... )
{
  std::cerr << "unknown exception!" << std::endl;
}