C ++ throw dereferenced指针

时间:2011-08-10 16:48:45

标签: c++

以下引发的异常对象的类型是什么:

问题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”

3 个答案:

答案 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