13

当需要dynamic_cast并且根本无法解决时,谁能给我一个真实的案例示例?我能想到的示例通常可以通过双重调度来解决。

如果约束太强,那么 dynamic_cast 通常是要走的路的例子也很好。

我希望看到真实的例子,而不是“它通常用于在类型树上下类型之间进行转换”。

4

5 回答 5

6

双重分派要求正在交互的类型对彼此的内部有深入的了解,因为它要求一个类调用另一个类的方法。dynamic_cast当您无法修改类的内部或不希望破坏相关类的封装时有效。

也就是说,双重调度对所涉及的类具有侵入性,而在dynamic_cast不知道类中的演员表的情况下工作。

dynamic_cast如果您不知道将调用的目标方法重载,也可以使用。例如,请参阅我昨天发布的这个问题

最后,双重调度并非没有它自己的麻烦

基类 Shape 必须知道所有派生类,从而导致循环依赖。如果从 Shape 派生一个新类(比如 Triangle),则必须更新 Shape 的接口和所有其他派生类的接口/实现。在某些情况下,这甚至不是一个选项:您可能没有 Shape 的源代码,或者不愿意或不允许修改它。

于 2011-07-01T20:17:06.160 回答
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!

如前所述,这是简化的。现实倾向于变得更加混乱。还有更多的代码。

干杯&hth。

于 2011-07-01T20:57:49.133 回答
0

我个人使用它来处理我的游戏引擎的某些部分。我有一个基实体类,我从中派生出各种其他实体。我将它们转换为基类类型,以便可以轻松地将它们存储到链表中。当我想检查列表中的特定条目是否属于某个实体时,我会将其动态转换为该类型。如果它返回 null,那么我知道它不是。

于 2011-07-01T20:44:19.030 回答
0

假设我们有一个我们正在使用的库,它旨在让我们从中派生一些类型:

class A {};
class B : public A {};
class C : public B {};

当我们派生我们的类型时,我们有一些对所有案例都通用的东西:

class CommonStuff {};
class D : public CommonStuff, public C {};

现在,当我们使用我们的库时,有一个回调类型为 A&(或 B& 或 C&)

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.

现在,把它和一粒盐放在一起,因为这可以解决。

于 2011-07-01T22:30:01.050 回答
0

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

于 2011-07-02T04:26:35.663 回答