我有两个函数a()
和b()
,它们有自己的异常类(连续a_exc
和b_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_exc
和b_exc
。当然,此块不能使用e.show()
,因为catched obj是std::logic_error
。
这就是我的问题。我想知道当被捕获的异常为show()
或std::logic_error
时,是否有机会在a_exc
catch块中调用b_exc
方法。我知道,如果我为show()
和a_exc
创建单独的catch块,则可以调用b_exc
,但我想使用一个 catch块来调用此方法。有可能吗?
答案 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
}
除了第二个更清晰,更易于维护和抵抗随后副本上的无意切片。
第一个是使用“代码查找代码”,这总是一个等待发生的维护灾难。
你的问题引发了更多问题:
a_exc
和b_exc
两种种类相同的错误?如果是这样,那么这就是一个多态基类,你可以优先考虑std::logic_error
您真的需要show()
方法吗?你能简单地在构造函数中构建what
字符串,并将此字符串传递给std::logic_error
的构造函数吗?如果这是可能的,这是我建议的路线。当您开始向异常添加特殊接口时,您需要了解此接口,从而污染整个代码库。如果您正在编写库,那么您现在已经污染了使用您库的每个应用程序。
假设您确实需要show
,并且a_exc
和b_exc
确实是两种相同的错误,我们仍然可以避免多态性。也许我们可以将'show'消息作为字符串,并在构造函数中构建它。现在只是数据。没有大惊小怪,没有并发症。
(完整)示例使用多态基类(a_exc
和b_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();
}
}