关于动态转换:C ++ dynamic_cast错误处理

c++ dynamic_cast error handling

是否有任何与dynamic_cast错误处理相关的良好做法(除非不需要时不使用它)? 我想知道我应该如何处理NULL并抛出bad_cast。
我应该同时检查两者吗? 而且,如果我抓到bad_cast或检测到NULL,我可能还是无法恢复...
现在,我使用断言来检查dynamic_cast是否返回了非NULL值。 您是否会接受代码审查的此解决方案?


如果dynamic_cast应该成功,那么最好使用boost::polymorphic_downcast,这有点像这样:

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

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

如果怀疑强制转换可能失败并且想要检测到它,请使用dynamic_cast并将其强制转换为引用类型。如果发生错误,此强制转换将抛出bad_cast,并会终止您的程序。 (如您所说,如果您无论如何都不会恢复,那就很好了)

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

仅在上下文中使用0指针时,才将dynamic_cast用作指针类型。您可能希望在if中使用它,如下所示:

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

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

要直接回答您的问题:我希望我给出的两个第一种选择之一是在代码中具有显式的assert :)


仅在投射引用时抛出bad_cast

1
dynamic_cast< Derived & >(baseclass)

强制转换指针时返回NULL

1
dynamic_cast< Derived * >(&baseclass)

因此,无需检查两者。

断言是可以接受的,但是很大程度上取决于上下文,然后,对于几乎所有断言来说都是如此……


是的,没有。

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

但是,以下顺序:

1
2
3
4
5
6
if (T1* t1 = dynamic_cast<T1*>(o))
{ }
if (T2* t2 = dynamic_cast<T2*>(o))
{ }
if (T3* t3 = dynamic_cast<T3*>(o))
{ }

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


这取决于... ;-)

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

但是,如果我要查询多态类型以获取接口不一定要实现的某些功能,那么我将使用指针强制转换,然后NULL不会是一个错误(除非当然,我希望确实能够使用该功能-但后来我就去找了参考演员……)


我同意"取决于"的答案,并添加"优美的降级效果":仅仅因为某个地方的转换失败不足以让应用程序失败(并且用户失去工作等)。我建议结合断言和防御性编程:

1
2
3
4
5
6
ptr = dynamic_cast<MyClass>(obj);
ASSERT(ptr);
if(ptr)
{
   // do stuff
}