24

是否有任何与 dynamic_cast 错误处理相关的良好做法(除非在您不需要时不使用它)?我想知道我应该如何处理它可以抛出的 NULL 和 bad_cast 。我应该检查两者吗?如果我捕捉到 bad_cast 或检测到 NULL,我可能无论如何都无法恢复……现在,我正在使用 assert 检查 dynamic_cast 是否返回非 NULL 值。你会在代码审查中接受这个解决方案吗?

4

5 回答 5

26

如果dynamic_cast 应该成功,那么改用它是一个好习惯boost::polymorphic_downcast,它有点像这样:

assert(dynamic_cast<T*>(o) == static_cast<T*>(o));
return static_cast<T*>(o);

这样,您将在调试构建中检测错误,同时避免发布构建中的运行时开销。

如果您怀疑强制转换可能会失败并且您想检测它,请使用dynamic_cast并强制转换为引用类型。如果出现错误,此演员将抛出bad_cast,并将取消您的程序。(这很好,如果你说,你无论如何都不会恢复)

T& t = dynamic_cast<T&>(o);
t.func(); //< Use t here, no extra check required

dynamic_cast仅当 0 指针在上下文中有意义时才使用指针类型。您可能希望if像这样使用它:

if (T* t = dynamic_cast<T*>(o)) {
    t->func(); //< Use t here, it is valid
}
// consider having an else-clause

使用最后一个选项,您需要确保如果dynamic_cast返回 0,则执行路径是有意义的。

直接回答你的问题:我更喜欢我给出的两个第一个替代方案之一,而不是assert在代码中有一个明确的:)

于 2008-10-29T10:19:51.867 回答
23

bad_cast 仅在转换引用时抛出

dynamic_cast< Derived & >(baseclass)

转换指针时返回 NULL

dynamic_cast< Derived * >(&baseclass)

因此,无需同时检查两者。

断言是可以接受的,但这在很大程度上取决于上下文,再说一次,几乎每个断言都是如此......

于 2008-10-29T10:21:21.363 回答
2

是和不是。

boost::polymorphic_downcast<>dynamic_cast<>在调试阶段处理错误肯定是一个不错的选择。但是值得一提的是,只有在可以预测编译时传递的多态类型polymorphic_downcast<>时才应该使用它,否则应该使用 代替它。dynamic_cast<>

然而,一系列:

if (T1* t1 = dynamic_cast<T1*>(o)) 
{ }
if (T2* t2 = dynamic_cast<T2*>(o)) 
{ }
if (T3* t3 = dynamic_cast<T3*>(o)) 
{ }

表示一个非常糟糕的设计,应该通过多态性虚函数来解决。

于 2008-11-15T09:50:11.597 回答
1

这取决于... ;-)

如果我真的希望dynamic_cast给我一些有用的东西,例如,如果我和其他人没有将多态类型添加到指向基类的指针的容器中,那么我将使用引用强制转换并让std::bad_cast我的应用程序终止 - 不会真的没什么可做的。

但是,如果我正在查询多态类型以获取它不一定必须实现的接口公开的某些功能,那么我会使用指针强制转换,然后 NULL 不会是错误(除非,当然,我希望这种能力真的存在——但后来我一开始就去找参考演员了……)

于 2008-10-29T10:16:44.073 回答
0

我同意“视情况而定”的答案,并添加“优雅降级”:仅仅因为某个地方的演员表失败并不足以让应用程序失败(并且用户失去他/她的工作等)。我建议结合使用断言和防御性编程:

ptr = dynamic_cast<MyClass>(obj);
ASSERT(ptr);
if(ptr)
{
   // do stuff
}
于 2008-10-29T10:21:36.013 回答