C ++中dynamic_cast的真实例子

时间:2011-07-01 20:00:27

标签: c++ dynamic-cast

任何人都可以给我一个真实世界的例子,当需要dynamic_cast并且根本无法解决时?我能想到的例子通常可以解决双重调度问题。

如果约束太强,那么通常采用dynamic_cast的例子也很不错。

我希望看到真实的例子,而不是“它通常用于在类型树上下输入类型”。

5 个答案:

答案 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_castreinterpret_cast显然不是正确的选择,因为它会引入切片。这里唯一的选择是dyanmic_cast

现在,带上一粒盐,因为这可以解决。

答案 4 :(得分:0)

您通常可以通过向A添加虚拟函数来替换dynamic_cast&lt; A *&gt;(...)。但是,如果A是来自第三方库的类,那么您无法更改它,因此您无法添加虚拟功能。所以你可能不得不使用dynamic_cast。