C++ 中的dynamic_cast 的真实示例

发布于 2024-11-18 12:05:37 字数 159 浏览 4 评论 0原文

有人能给我一个真实世界的例子,说明需要dynamic_cast并且根本无法解决的情况吗?我能想到的例子通常可以通过双重调度来解决。

如果约束太强,那么通常使用dynamic_cast 的示例也很好。

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

Can anybody give me a real world example of a case when dynamic_cast is needed and can't be worked around at all? Examples I can think of can generally be worked around with double dispatch.

If the constraint is too strong, an example where dynamic_cast is generally the way to go would also be nice.

I'd like to see real examples instead of "it's normally used to cast between types up and down a type tree".

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

那支青花 2024-11-25 12:05:37

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

也就是说,双重调度对所涉及的类是侵入性的,而dynamic_cast在不了解类中的强制转换的情况下工作。

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

最后,双重调度也有它自己的麻烦

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

Double dispatch requires that the types that are interacting have intimate knowledge of each other's innards, as it requires that one class call methods on the other class. dynamic_cast works when you cannot modify the innards of a class, or do not wish to break encapsulation of the classes in question.

That is, double dispatch is invasive on the classes involved, while dynamic_cast works without knowledge of the cast in the classes.

You can also use dynamic_cast if you don't know the target method overload which will be invoked. For an example, see this question I posted yesterday.

Finally, double dispatch does not come without it's own headaches

The base class Shape must know about all the derived classes, resulting in circular dependencies. If you derive a new class from Shape (say Triangle), you must update the interface of Shape and the interface/implementation of all the other derived classes. In some cases this is not even an option: you may not have the source code for Shape, or not be willing or permitted to modify it.

流绪微梦 2024-11-25 12:05:37

“根本无法解决”的约束太强了。任何 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!

如前所述,这已被简化。现实往往会更加混乱。并且有更多的代码。

干杯&嗯。

The constraint "can't be worked around at all" is too strong. Any C++ feature can be emulated in C. All you have to do to work around the feature, so to speak, is to use that C code in C++. For example, MFC, a library originating from the depths of time before the 1998 language standardization, offered and still offers its own kind of dynamic cast.

One example where you generally need dynamic casting is the visitor pattern, e.g. as used for event handling. The idea of visitation is to centralize the dynamic casting, so that instead of a zillion dynamic casts peppered throughout the code, there is a single one:

#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 );
}

The output of this program is Foo Fighter!.

As mentioned, this is simplified. Reality has a tendency to be a bit more messy. And with far more code.

Cheers & hth.

如果没结果 2024-11-25 12:05:37

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

I personally use it for working through certain parts of my game engine. I have a base entity class from which I derive various other entities from. I cast them to the base class type so I can store them easily into a linked list. When I want to check to see if a particular entry in my list is of a certain entity, I dynamic_cast it to that type. If it returns null, then I know it's not.

水波映月 2024-11-25 12:05:37

假设我们有一个库,我们正在使用它来派生一些类型:

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

现在,对此持保留态度,因为这是可以解决的。

Let's say we have a library that we're using that is meant for us to derive some types from:

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

And when we're deriving our types, we have some things that are common to all of our cases:

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

Now, as we're working with our library, and there is a callback that takes type A& (or B& or C&)

void some_func(A& obj);

And assume in that function it expects polymorhpic behavior, but we need to access some of our CommonStuff:

void some_func(A& obj)
{
    CommonStuff& comn = dynamic_cast<CommonStuff&>(obj);
}

Since there's no direct correlation between A and CommonStuff, we cannot use static_cast, reinterpret_cast is obviously not the right choice as it will introduce slicing. The only option here is dyanmic_cast.

Now, take this with a grain of salt, because this could be worked around.

倦话 2024-11-25 12:05:37

You can often replace dynamic_cast<A*>(...) by adding a virtual function to A. However, if A is a class from a third party library then you can't change it so you can't add a virtual function to it. So you may have to use dynamic_cast.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文