从其基类捕获的自己的异常类调用方法
Calling method from own exception class catched by its base class
我有两个函数a()
和b()
,它们有自己的继承自std::logic_error
的异常类(连续a_exc
和b_exc
)。
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()
,因为捕获的对象是std::logic_error
。
我的问题是。我想知道当捕获的异常是a_exc
或b_exc
时,是否有机会在std::logic_error
捕获块中调用show()
方法。我知道,如果我为a_exc
和b_exc
创建单独的捕获块,调用show()
是可能的,但我想使用一个捕获块来调用此方法。这可能吗?
可以,只要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();
}
在Coliru上观看。但是,在catch
异常处理程序中调用其他可能throw
的函数通常是一个坏主意。
关于设计的几点思考
在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();
}
}
您应该考虑创建派生类型:
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:
catch (const show_exc& e) {
// ..
}
catch (const std::logic_error& e) {
// ..
}
- C++/CLI System.AccessViolation在托管类中调用非托管函数时出现异常
- 尝试在 QT 项目中调用 Java 代码时未找到类异常
- 调用参数不是原子参数的函数是此代码引发异常的原因吗?
- 从 C# 调用 C++ DLib 会导致错误的分配异常
- 在 postOrderDelete 上调用析构函数时引发的异常
- memcpy() 在一个类中被调用以复制到另一个类变量中后会引发异常
- 为什么在析构函数中引发异常时不调用重载删除
- CPP 异常获取抛出调用方的详细信息
- 为什么要抛出引用调用复制构造函数的异常?
- 析构函数中的互斥锁C++在 Python 中调用 exit() 时会导致异常
- 调试"在抛出 ..) 实例后终止调用",当异常 _should_ 被捕获时
- 调用系统调用函数时出现异常
- 如果从在其他函数中调用的函数引发异常会发生什么情况
- C++函数中引发异常并在调用方中捕获它
- 防止线程在处理异常后在分离时调用 std::terminate()
- 如果从类成员初始值设定项引发的异常调用 std::terminate()
- 从 c# 内存不足异常调用 c++ 委托
- 析构函数的异常调用
- 加密++异常调用消息结束
- 避免对特定异常调用析构函数