以下引发的异常对象的类型是什么:
问题1> range_error r("error"); throw r;
正确答案为> range_error的对象
问题2> exception *p = &r; throw *p;
ANSWER2>切片的异常对象
问题3> exception *p = &r; throw p;
ANSWER3>抛出指向range_error的指针。捕获处理可以通过动态绑定访问range_error成员函数。
我能解决这些问题吗?
//更新并编译并在VS2010上运行
#include <iostream>
using namespace std;
class ExClassA
{
public:
virtual void PrintMe() const
{
cout << "ExClassA" << endl;
}
};
class ExClassB : public ExClassA
{
public:
virtual void PrintMe() const
{
cout << "ExClassB" << endl;
}
};
int main(int argc, char* argv[])
{
ExClassB exClassB;
ExClassA *p = &exClassB;
try
{
throw *p;
}
catch (const ExClassA& e)
{
e.PrintMe();
}
try
{
throw p;
}
catch (const ExClassA* e)
{
e->PrintMe();
}
}
上述程序的第一个try-catch打印“ExClassA”
上述程序的第二个try-catch打印“ExClassB”
答案 0 :(得分:6)
抛出一个对象总是会导致抛出的对象是您投掷的对象的副本,具体取决于该对象的静态类型。因此,您的前两个答案是正确的。
第三个稍微复杂一点。如果您catch(range_error*)
,您将不会捕获异常,因为类型不匹配。如果您catch(exception*)
,您将无法访问捕获指针中range_error
的成员;你可以dynamic_cast
指针返回一个range_error指针。
答案 1 :(得分:5)
我认为你在这三个方面都是正确的。抛出对象的类型(IIRC)是被抛出对象的静态类型。我将不得不深入研究标准一段时间才能找到确切的报价,但一个简单的例子似乎证实了这一点:
struct base {};
struct derived : base {};
void t() {
derived d;
base * b = &d;
throw *b;
}
int main() {
try {
t();
} catch ( derived const & ) {
std::cout << "derived" << std::endl;
} catch ( base const & ) {
std::cout << "base" << std::endl;
}
}
如果使用了抛出的对象的动态类型,那么*b
将具有类型derived
并且第一个catch
将成功,但根据经验,第二个catch
是执行(g ++)。
在最后一种情况下,抛出的对象是指向exception
对象的range_error
指针。稍有不同的是可以捕获的内容,编译器不会捕获catch (range_error*)
块。答案是正确的,但我会指定指针的类型,与指针的类型一样多。 (指针的类型在某种程度上隐含在答案中)
答案 2 :(得分:3)
所有三个答案都是正确的。请注意,你必须抓住一个 指针类型在第三种情况下。
抛出异常的常用方法是:
throw range_error("error");
在投掷站点,您通常知道您的确切类型 想扔。关于我能想到的唯一例外是什么时候 异常作为参数传递,例如:
void f( std::exception const& whatToDoInCaseOfError )
{
// ...
throw whatToDoInCaseOfError; // slices
}
这不是一个常见的情况,但如果你想支持它,你需要一个
使用虚拟raise
分隔您自己的异常层次结构
功能:
class MyExceptions
{
public:
virtual ~MyExceptions() {}
virtual void raise() const = 0;
};
template<typename ExceptionType>
class ConcreteException : public ExceptionType, public MyExceptions
{
public:
virtual void raise() const
{
throw *this;
}
};
客户端代码然后包装他想要抛出的异常
ConcreteException
,而您在其上调用raise
函数
而不是直接调用throw
。