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

时间:2016-09-19 22:51:18

标签: c++

我有两个函数a()b(),它们有自己的异常类(连续a_excb_exc),它们继承自std::logic_error

void a() { (...) throw a_exc(some_val) }
void b() { (...) throw b_exc(some_val) }

class a_exc : public std::logic_error
{
private:
  int foo;
public:
  a_exc(int val, const std::string& what_msg="Msg.")
    : std::logic_error(what_msg), foo(val) {}
  void show() { //show foo }
}

class b_exc : public std::logic_error
{
private:
  std::string bar;
public:
  a_exc(std::string val, const std::string& what_msg="Msg.")
    : std::logic_error(what_msg), bar(val) {}
  void show() { //show bar }
}

我们说我有以下部分代码:

try {
  a(); 
  b(); 
}
catch (const std::logic_error& e)
{
    e.what();
    // e.show();
}

catch (const std::logic_error& e)同时捕获a_excb_exc。当然,此块不能使用e.show(),因为catched obj是std::logic_error

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

3 个答案:

答案 0 :(得分:2)

您可以,只要$(icon).closest('tr').css('background-color', 'yellow'); requestAnimationFrame(function () { if (confirm(message)) { } }); show()成员函数:

const

Live on Coliru。但是,在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(); } 异常处理程序中调用可能throw的其他函数通常是个坏主意。

答案 1 :(得分:1)

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

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) {
  // ..
}

答案 2 :(得分:1)

关于设计的一些想法。

在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
  }
}

在逻辑上与:

相同
catch(Y& t)
{
  // it's a Y
}
catch(Z& z)
{
  // it's a Z
}
catch(X& x)
{
  // it's an X
}

除了第二个更清晰,更易于维护和抵抗随后副本上的无意切片。

第一个是使用“代码查找代码”,这总是一个等待发生的维护灾难。

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

  1. a_excb_exc两种种类相同的错误?如果是这样,那么这就是一个多态基类,你可以优先考虑std::logic_error

  2. 您真的需要show()方法吗?你能简单地在构造函数中构建what字符串,并将此字符串传递给std::logic_error的构造函数吗?如果这是可能的,这是我建议的路线。当您开始向异常添加特殊接口时,您需要了解此接口,从而污染整个代码库。如果您正在编写库,那么您现在已经污染了使用您库的每个应用程序。

  3. 假设您确实需要show,并且a_excb_exc确实是两种相同的错误,我们仍然可以避免多态性。也许我们可以将'show'消息作为字符串,并在构造函数中构建它。现在只是数据。没有大惊小怪,没有并发症。

  4. (完整)示例使用多态基类(a_excb_exc 种类相同的东西

    #include <stdexcept>
    #include <string>
    
    struct showable_logic_error : std::logic_error
    {
        using std::logic_error::logic_error;
    
        virtual void show() const = 0;
    };
    
    class a_exc : public showable_logic_error
    {
    private:
        int foo;
    public:
        a_exc(int val, const std::string& what_msg="Msg.")
        : showable_logic_error(what_msg)
        , foo(val)
        {}
    
        void show() const override
        {
            //show foo
        }
    };
    
    class b_exc : public showable_logic_error
    {
    private:
        std::string bar;
    public:
        b_exc(std::string val, const std::string& what_msg="Msg.")
        : showable_logic_error(what_msg)
        , bar(val)
        {}
    
        void show() const override
        { //show bar
        }
    };
    
    void a() { throw a_exc(1); }
    void b() { throw b_exc("b"); }
    
    int main()
    {
        try
        {
            a();
        }
        catch(showable_logic_error const& e)
        {
            e.show();
        }
    }
    

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

    #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();
        }
    }