任何人都可以给我一个真实世界的例子,当需要dynamic_cast并且根本无法解决时?我能想到的例子通常可以解决双重调度问题。
如果约束太强,那么通常采用dynamic_cast的例子也很不错。
我希望看到真实的例子,而不是“它通常用于在类型树上下输入类型”。
答案 0 :(得分:6)
双重调度要求相互作用的类型对彼此的内部有深入的了解,因为它需要在另一个类上调用一个类。当dynamic_cast
无法修改类的内部结构,或者不希望破坏相关类的封装时,dynamic_cast
可以正常工作。
也就是说,双重调度对所涉及的类是侵入性的,而dynamic_cast
在不知道类中的强制转换的情况下工作。
如果您不知道将调用的目标方法重载,也可以使用{{1}}。有关示例,请参阅this question I posted yesterday。
最后,double dispatch does not come without it's own headaches
基类Shape必须知道所有派生类,从而产生循环依赖关系。如果从Shape派生一个新类(比如Triangle),则必须更新Shape的接口和所有其他派生类的接口/实现。在某些情况下,这甚至不是一个选项:您可能没有Shape的源代码,或者不愿意或允许修改它。
答案 1 :(得分:1)
约束“根本无法解决”太强大了。任何C ++特性都可以用C模拟。所有你需要做的就是使用C ++中的C代码来解决这个特性。例如,MFC,一个源自1998语言标准化之前的深度的图书馆,提供并仍然提供自己的动态演员。
您通常需要动态投射的一个示例是访问者模式,例如用于事件处理。访问的想法是集中动态投射,以便在整个代码中不再包含数以万计的动态强制转换,只有一个:
#include <stdio.h>
void say( char const s[] ) { printf( "%s\n", s ); }
struct Event
{
struct Handler
{
virtual void onEvent( Event& ) = 0;
};
virtual void dispatchTo( Handler& aHandler )
{
aHandler.onEvent( *this );
}
template< class SpecificEvent >
static void dispatch( SpecificEvent& e, Handler& aHandler )
{
typedef typename SpecificEvent::Handler SpecificHandler;
// The single dynamic cast:
if( SpecificHandler* p = dynamic_cast<SpecificHandler*>( &aHandler ) )
{
p->onEvent( e );
}
else
{
e.Event::dispatchTo( aHandler );
}
}
};
struct FooEvent
: Event
{
struct Handler
{
virtual void onEvent( FooEvent& ) = 0;
};
virtual void dispatchTo( Event::Handler& aHandler )
{
dispatch( *this, aHandler );
}
};
struct Plane
: Event::Handler
{
virtual void onEvent( Event& ) { say( "An event!" ); }
};
struct Fighter
: Plane
, FooEvent::Handler // Comment out this line to get "An event!".
{
virtual void onEvent( FooEvent& ) { say( "Foo Fighter!" ); }
};
void doThingsTo( Plane& aPlane )
{
FooEvent().dispatchTo( aPlane );
}
int main()
{
Fighter plane;
doThingsTo( plane );
}
此程序的输出为Foo Fighter!
。
如上所述,这是简化的。现实有一种更加凌乱的倾向。还有更多的代码。
干杯&amp;第h
答案 2 :(得分:0)
我个人用它来处理游戏引擎的某些部分。我有一个基本实体类,我从中派生出各种其他实体。我将它们转换为基类类型,以便我可以轻松地将它们存储到链表中。当我想检查我的列表中的特定条目是否属于某个实体时,我将其dynamic_cast到该类型。如果它返回null,那么我知道它不是。
答案 3 :(得分:0)
假设我们有一个我们正在使用的库,这对我们来说是从以下类型派生的:
class A {};
class B : public A {};
class C : public B {};
当我们推导出我们的类型时,我们会遇到一些对我们所有情况都很常见的事情:
class CommonStuff {};
class D : public CommonStuff, public C {};
现在,我们正在使用我们的库,并且有一个回调类型为A&amp; (或B&amp;或C&amp;)
void some_func(A& obj);
并假设在该函数中它期望多态行为,但我们需要访问我们的一些CommonStuff:
void some_func(A& obj)
{
CommonStuff& comn = dynamic_cast<CommonStuff&>(obj);
}
由于A和CommonStuff之间没有直接的关联,我们不能使用static_cast
,reinterpret_cast
显然不是正确的选择,因为它会引入切片。这里唯一的选择是dyanmic_cast
。
现在,带上一粒盐,因为这可以解决。
答案 4 :(得分:0)
您通常可以通过向A添加虚拟函数来替换dynamic_cast&lt; A *&gt;(...)。但是,如果A是来自第三方库的类,那么您无法更改它,因此您无法添加虚拟功能。所以你可能不得不使用dynamic_cast。