C ++:当捕获基类时,通过引用抛出一个派生类不起作用 [英] C++: Throwing a derived class by reference does not work when catching base class

查看:123
本文介绍了C ++:当捕获基类时,通过引用抛出一个派生类不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用基类 Exception 抛出我自己的异常。有一个虚方法 print ,它将被子类覆盖。我只捕获类型异常& 并使用 print 获取特定错误。问题是,一旦我抛出一个子类的引用,它就像是基类。



这里是一个例子:

  #include< iostream> 
using namespace std;

类别异常
{
public:
virtual void print()
{
cout< 异常<< endl;
}
};

class IllegalArgumentException:public Exception
{
public:
virtual void print()
{
cout< IllegalArgumentException< endl;
}
};

int main(int argc,char ** argv)
{
try
{
IllegalArgumentException i;
异常& ref = i;

cout<< ref.print:;
ref.print();

throw ref;
}
catch(Exception& e)
{
cout< catched:;
e.print();
}
}

此示例的输出为:

  ref.print:IllegalArgumentException 
catched:Exception

使用引用应该从正在使用的派生类中得到 print 方法。在try块内引用使用它。为什么不捕获异常& 的行为像 IllegalArgumentException ,如何获得这种行为?



以下代码似乎可以做到:

  try 
{
IllegalArgumentException i;
Exception * pointer =& i;

throw指针;
}
catch(Exception * e)
{
cout< pointer catched:;
e-> print();
}

但不会在try块的范围外?这样做是有风险的,如果我在堆上分配内存来解决这个问题,我有责任删除内的catch块是不漂亮。

throw 隐式复制,这样你就可以解决这个问题了。


一个临时对象通过从throw的操作数的静态类型中删除任何顶级的 cv-qualifiers ,并从array of操作数调整类型来确定 T 或函数返回 T 指向 T 或指向返回 T 的函数的指针。临时值是一个左值,用于初始化在匹配的处理程序中命名的变量。如果异常对象的类型是不完整的类型或指向不完整类型的指针(可能是cv限定的) void 程序是不成形的。除了这些限制和15.3中提到的类型匹配限制外, throw 的操作数完全作为调用中的函数参数或return语句的操作数处理。


我已经看到一些代码库通过抛出指向异常而不是直接对象的工作,但我个人重新考虑您的需要,首先这样做。


I want to throw my own exceptions with the base class Exception. There is a virtual method print which will be overwritten by the subclasses. I only catch the type Exception& and use print to get the specific error. The problem is that once I throw a reference of a subclass it is trated as if it were the base class.

Here is an example:

#include <iostream>
using namespace std;

class Exception
{
    public:
        virtual void print()
        {
            cout << "Exception" << endl;
        }
};

class IllegalArgumentException : public Exception
{
    public:
        virtual void print()
        {
            cout << "IllegalArgumentException" << endl;
        }
};

int main(int argc, char **argv)
{
    try
    {
        IllegalArgumentException i;
        Exception& ref = i;

        cout << "ref.print: ";
        ref.print();

        throw ref;
    }
    catch(Exception& e)
    {
        cout << "catched: ";
        e.print();
    }
}

The output of this example is:

ref.print: IllegalArgumentException
catched: Exception

Using a reference should result in the print method from the derived class being used. Inside the try block the reference does use it. Why doesn't the catched Exception& act like an IllegalArgumentException and how can I get that behavior?

The following code seems to do what it is supposed to:

try
{
    IllegalArgumentException i;
    Exception* pointer = &i;

    throw pointer;
}
catch(Exception* e)
{
    cout << "pointer catched: ";
    e->print();
}

but doesn't the pointer become possibly invalid outside the scope of the try block? It would then be risky to do this and if I allocate memory on the heap to get around that problem I have the responsibility for the deletion inside the catch block which isn't pretty either. So how would you solve the problem?

解决方案

throw implicitly copies, and consequently slices. Quoting C++11, §15.1/3:

A throw-expression initializes a temporary object, called the exception object, the type of which is determined by removing any top-level cv-qualifiers from the static type of the operand of throw and adjusting the type from "array of T" or "function returning T" to "pointer to T" or "pointer to function returning T", respectively. The temporary is an lvalue and is used to initialize the variable named in the matching handler. If the type of the exception object would be an incomplete type or a pointer to an incomplete type other than (possibly cv-qualified) void the program is ill-formed. Except for these restrictions and the restrictions on type matching mentioned in 15.3, the operand of throw is treated exactly as a function argument in a call or the operand of a return statement.

I've seen a handful of codebases that work around this by throwing pointers to exceptions rather than objects directly, but personally I'd just reconsider your "need" to do this in the first place.

这篇关于C ++:当捕获基类时,通过引用抛出一个派生类不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆