Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/137.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 从基类捕获的自己的异常类调用方法_C++ - Fatal编程技术网

C++ 从基类捕获的自己的异常类调用方法

C++ 从基类捕获的自己的异常类调用方法,c++,C++,我有两个函数a和b,它们分别拥有自己的异常类a_exc和b_exc,它们继承自std::logic_error 假设我有以下部分代码: try { a(); b(); } catch (const std::logic_error& e) { e.what(); // e.show(); } catch const std::logic_error&e捕获a_exc和b_exc。当然,此块不能使用e.show,因为捕获的对象是std::logic_error

我有两个函数a和b,它们分别拥有自己的异常类a_exc和b_exc,它们继承自std::logic_error

假设我有以下部分代码:

try {
  a(); 
  b(); 
}
catch (const std::logic_error& e)
{
    e.what();
    // e.show();
}
catch const std::logic_error&e捕获a_exc和b_exc。当然,此块不能使用e.show,因为捕获的对象是std::logic_error

这是我的问题。我想知道当捕获的异常是a_exc或b_exc时,是否有机会在std::logic_error catch块中调用show方法。我知道,如果我为a_exc和b_exc创建单独的catch块,则可以调用show方法,但我只想使用一个catch块来调用此方法。有可能吗?

如果show是常量成员函数,您可以:

catch (const std::logic_error& e)
{
    e.what();
    if(const a_exc* a = dynamic_cast<const a_exc*>(&e))
        a->show();
    else if(const b_exc* b = dynamic_cast<const b_exc*>(&e))
        b->show();
}
看到了。不过,调用其他可能会抛出catch异常处理程序的函数通常不是一个好主意。

如果show是const成员函数,则可以:

catch (const std::logic_error& e)
{
    e.what();
    if(const a_exc* a = dynamic_cast<const a_exc*>(&e))
        a->show();
    else if(const b_exc* b = dynamic_cast<const b_exc*>(&e))
        b->show();
}

看到了。但是,调用其他可能抛出catch异常处理程序的函数通常是个坏主意。

应该考虑创建派生类型:

struct show_exc : public std::logic_error
{
    virtual void show() = 0;
};

class a_exc : public show_exc
{
    int foo_;
public:
    virtual void show() override { /*...*/ };
};
然后使用一个明显的捕捉:

catch (const show_exc& e) {
  // ..
}
catch (const std::logic_error& e) {
  // ..
}

您应该考虑创建派生类型:

struct show_exc : public std::logic_error
{
    virtual void show() = 0;
};

class a_exc : public show_exc
{
    int foo_;
public:
    virtual void show() override { /*...*/ };
};
然后使用一个明显的捕捉:

catch (const show_exc& e) {
  // ..
}
catch (const std::logic_error& e) {
  // ..
}

关于设计的一些思考

在catch块中查询异常类型在逻辑上与只提供两个catch块没有什么不同

要明确的是:

catch(X& x)
{
  if (dynamic_cast<Y*>(&x)) {
    // it's a Y
  }
  if (dynamic_cast<Z*>(&z)) {
    // it's a Z
  }
  else {
    // it's an X
  }
}
除了第二个更清晰、更易于维护,并且可以防止在后续副本上无意中进行切片

首先是使用代码查找代码,这总是一个等待发生的维护灾难

你的问题引发了更多的问题:

a_exc和b_exc是两种相同的错误吗?如果是这样,这就需要一个多态基类,您可以优先捕获它而不是std::logic\u error

你真的需要展示方法吗?您可以简单地在构造函数中构建what字符串,并将该字符串传递给std::logic\u error的构造函数吗?如果可能的话,我会推荐这条路线。当您开始向异常添加特殊接口时,您就需要了解这个接口,从而污染了整个代码库。如果您正在编写库,那么您现在已经污染了使用库的每个应用程序

假设您确实需要show,并且a_exc和b_exc实际上是两种相同的错误,我们仍然可以避免多态性。也许我们可以将“show”消息作为字符串支撑,并在构造函数中构建它。现在只是数据。没有麻烦,没有麻烦

使用多态基类a_-exc和b_-exc的完整示例是相同的

不需要多态性的完整示例:

#include <stdexcept>
#include <string>
#include <sstream>

struct message_builder
{
    template<class T>
    static std::string build_what(const std::string& whatstr, T&& info)
    {
        std::ostringstream ss;
        ss << whatstr << " : " << info;
        return ss.str();
    }
};

class a_exc
: public std::logic_error
, private message_builder
{
public:
    a_exc(int val, const std::string& what_msg="Msg.")
    : std::logic_error(build_what(what_msg, val))
    {}

};

class b_exc
: public std::logic_error
, private message_builder
{
private:
    std::string bar;
public:
    b_exc(std::string val, const std::string& what_msg="Msg.")
    : std::logic_error(build_what(what_msg, std::move(val)))
    , bar(val)
    {}

};

void a() { throw a_exc(1); }
void b() { throw b_exc("b"); }

int main()
{
    try
    {
        a();
    }
    catch(std::logic_error const& e)
    {
        e.show();
    }
}

关于设计的一些思考

在catch块中查询异常类型在逻辑上与只提供两个catch块没有什么不同

要明确的是:

catch(X& x)
{
  if (dynamic_cast<Y*>(&x)) {
    // it's a Y
  }
  if (dynamic_cast<Z*>(&z)) {
    // it's a Z
  }
  else {
    // it's an X
  }
}
除了第二个更清晰、更易于维护,并且可以防止在后续副本上无意中进行切片

首先是使用代码查找代码,这总是一个等待发生的维护灾难

你的问题引发了更多的问题:

a_exc和b_exc是两种相同的错误吗?如果是这样,这就需要一个多态基类,您可以优先捕获它而不是std::logic\u error

你真的需要展示方法吗?您可以简单地在构造函数中构建what字符串,并将该字符串传递给std::logic\u error的构造函数吗?如果可能的话,我会推荐这条路线。当您开始向异常添加特殊接口时,您就需要了解这个接口,从而污染了整个代码库。如果您正在编写库,那么您现在已经污染了使用库的每个应用程序

假设您确实需要show,并且a_exc和b_exc实际上是两种相同的错误,我们仍然可以避免多态性。也许我们可以将“show”消息作为字符串支撑,并在构造函数中构建它。现在只是数据。没有麻烦,没有麻烦

使用多态基类a_-exc和b_-exc的完整示例是相同的

不需要多态性的完整示例:

#include <stdexcept>
#include <string>
#include <sstream>

struct message_builder
{
    template<class T>
    static std::string build_what(const std::string& whatstr, T&& info)
    {
        std::ostringstream ss;
        ss << whatstr << " : " << info;
        return ss.str();
    }
};

class a_exc
: public std::logic_error
, private message_builder
{
public:
    a_exc(int val, const std::string& what_msg="Msg.")
    : std::logic_error(build_what(what_msg, val))
    {}

};

class b_exc
: public std::logic_error
, private message_builder
{
private:
    std::string bar;
public:
    b_exc(std::string val, const std::string& what_msg="Msg.")
    : std::logic_error(build_what(what_msg, std::move(val)))
    , bar(val)
    {}

};

void a() { throw a_exc(1); }
void b() { throw b_exc("b"); }

int main()
{
    try
    {
        a();
    }
    catch(std::logic_error const& e)
    {
        e.show();
    }
}

次要细节,但show不是const成员函数,因此需要处理a_exc::show和b_exc::show不相关的事实。因此,为调用show方法的a_exc和b_exc设置单独的catch块是否更好?@mdjdrn1,由您决定。您可以创建一个从std::logic_error派生的公共基类,并提供虚拟成员函数来显示a_exc和b_exc应该从哪个派生并重写。或者,您可以创建多个catch块,就像不需要通过const引用捕获异常一样,因此如果需要调用非const成员函数,则只需取出所有const。但是,当您使用show函数时,show函数要么需要是noexcept,要么需要包装在try..catch块中
叫它。除非你喜欢未定义的行为,但show不是一个const成员函数,因此需要处理a_exc::show和b_exc::show不相关的事实。那么,为调用show方法的a_exc和b_exc设置单独的catch块是否更好?@mdjdrn1,由你决定。您可以创建一个从std::logic_error派生的公共基类,并提供虚拟成员函数来显示a_exc和b_exc应该从哪个派生并重写。或者,您可以创建多个catch块,就像不需要通过const引用捕获异常一样,因此如果需要调用非const成员函数,则只需取出所有const。但是,调用show函数时,它要么需要是noexcept,要么需要包装在try..catch块中。除非你喜欢未定义的行为,否则你希望得到的是模板捕获,这是罕见的=当前不存在的库将其伪装成模板虚拟。你希望得到的是模板捕获,这是罕见的=当前不存在的库将其伪装成模板虚拟。是的,但那是在做完全不同的事情。它将不再捕获std::logic_错误-没有OP试图避免的另一个捕获块。是的,但这做了完全不同的事情。它将不再捕获std::logic_错误-没有OP试图避免的另一个捕获块。感谢您提供如此全面和有价值的答案@我很高兴。谢谢你的欣赏,谢谢你如此全面而有价值的回答@我很高兴。谢谢你的欣赏。